
在360某Web应用安全开发项目中,通过分析用户输入处理逻辑,定位并修复了SQL注入漏洞,通过参数化查询技术有效阻断恶意SQL执行,修复后漏洞复现率降至0,系统安全评分提升约15%。
SQL注入的核心是用户输入未被正确过滤或转义,导致恶意SQL语句绕过验证,直接执行数据库操作。类比:数据库查询就像一个“安全过滤器”,正常输入是“用户名=张三”,但恶意输入“用户名=张三’or’1’=’1”会绕过过滤,让数据库执行非法查询(如返回所有用户数据)。关键点:输入验证、参数化查询(预编译语句)是防止注入的核心手段。
| 方法 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 传统输入验证 | 对用户输入进行字符过滤(如转义单引号) | 依赖手动编写过滤规则,易遗漏复杂攻击(如多字节字符、注释绕过) | 适用于简单场景,但复杂攻击可能绕过 | 需持续更新规则,维护成本高 |
| 参数化查询(预编译) | 将用户输入作为参数传递,数据库引擎处理 | 自动处理特殊字符,防止注入 | 适用于所有数据库操作,尤其是动态SQL | 需支持数据库的预编译语法(如PreparedStatement) |
漏洞场景:用户登录接口(伪代码)
String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";
ResultSet rs = stmt.executeQuery(sql);
当用户输入 admin' or '1'='1 时,SQL变为:
SELECT * FROM users WHERE username='admin' or '1'='1' AND password='pwd' → 条件恒为真,返回所有用户。
修复方案(参数化查询):
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE username=? AND password=?");
ps.setString(1, username); // 参数1绑定用户名
ps.setString(2, password); // 参数2绑定密码
ResultSet rs = ps.executeQuery();
数据库引擎将 ? 视为参数,自动转义特殊字符,防止注入。
“我参与过360内部一个Web应用的安全开发项目,目标是加固用户认证模块。当时发现一个SQL注入漏洞,具体是在用户登录接口中,用户名和密码的输入未被正确处理,导致恶意SQL语句绕过验证。分析过程:通过Fuzzing工具(如OWASP ZAP)模拟不同输入,发现输入为admin' or '1'='1时,数据库返回了所有用户数据。检查代码逻辑后,发现使用的是拼接SQL字符串(sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";),没有对输入转义或参数化。修复方案是将拼接改为参数化查询,用PreparedStatement将用户输入作为参数传递,数据库引擎自动处理特殊字符。实施效果:修复后漏洞复现失败,系统安全测试中该漏洞不再出现,用户认证模块的渗透测试评分提升了约15%。”
问:你如何确定是SQL注入?
答:通过Fuzzing工具测试不同输入,观察数据库返回结果变化,结合代码逻辑分析输入处理方式(如拼接SQL vs 参数化)。
问:为什么参数化查询能解决?
答:参数化查询将用户输入与SQL语句分离,数据库引擎不会将输入当作SQL代码执行,而是作为参数处理,自动转义特殊字符,阻断注入。
问:有没有考虑其他输入验证方法?
答:比如手动转义,但容易遗漏复杂攻击(如多字节字符、注释绕过),而参数化查询更通用,能覆盖所有情况。
问:修复后有没有做回归测试?
答:是的,通过编写单元测试和集成测试用例,覆盖正常和异常输入,确保修复后功能正常且无新漏洞。