程序员如何做「安全编码」:不是多余,是必须
安全漏洞是程序员最容易被忽视的问题之一。
不是因为不重要,而是因为很多人觉得"不会有人攻击我"。
一、为什么需要安全编码
1. 安全漏洞无处不在
每一个没处理好的输入,都可能是攻击入口。
2. 安全问题代价高
数据泄露 = 信任损失 + 赔偿 + 法律风险。
3. 攻击成本低
自动化工具让攻击变得容易。
二、常见的安全漏洞
1. SQL 注入
用户输入没有转义,直接拼到 SQL 里。
// 危险
String sql = "SELECT * FROM users WHERE name = '" + name + "'";
// 安全
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?");
ps.setString(1, name);
2. XSS(跨站脚本攻击)
用户在页面执行恶意脚本。
<!-- 危险:直接输出用户输入 -->
<p>{{ userInput }}</p>
<!-- 安全:转义输出 -->
<p>{{ escape(userInput) }}</p>
3. CSRF(跨站请求伪造)
诱导用户执行非预期的操作。
防御:使用 CSRF Token。
4. 敏感信息泄露
密码、密钥存在代码里或日志里。
三、安全编码的原则
1. 输入校验
所有用户输入都是不可信的。
校验格式、长度、类型。
2. 输出转义
输出到 HTML、SQL、Shell 时要转义。
3. 最小权限原则
代码只申请需要的权限,不要过度授权。
4. 敏感数据加密
密码、密钥、个人信息要加密存储和传输。
5. 不要信任任何外部数据
用户输入、第三方 API、配置文件——都可能是攻击来源。
四、安全工具
1. 扫描工具
- SonarQube(代码质量 + 安全)
- OWASP ZAP(Web 安全扫描)
2. 依赖检查
- Maven:dependency-check
- npm:npm audit
3. 咸鱼验证
- 静态分析(SAST)
- 动态分析(DAST)
五、安全 checklist
- [ ] 所有用户输入校验
- [ ] SQL 使用参数化查询
- [ ] 输出转义
- [ ] CSRF Token
- [ ] 敏感数据加密
- [ ] 密码加密(不要明文)
- [ ] 不在日志里打印敏感信息
- [ ] 依赖更新到安全版本
六、一句话总结
安全编码 = 输入校验 + 输出转义 + 最小权限 + 敏感数据加密 + 定期扫描。