1. 使用预编译语句(Prepared Statements)+ 参数化查询
这是最推荐的防御手段,适用于几乎所有主流语言和数据库(如 Java 的 PreparedStatement
、Python 的 cursor.execute()
参数方式、PHP 的 PDO 等)。
原理:
- SQL 语句与数据参数分离。
- 数据不会被解释为 SQL 语句的一部分,从而彻底阻断注入的通路。
# Python 示例
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (user_input, password_input))
底层逻辑:
数据库驱动在发送 SQL 前会将语句结构和参数分离处理,参数作为“值”绑定在语法树中,攻击者无法篡改语法结构。
2. ORM 框架的使用(如 Hibernate, Django ORM, SQLAlchemy)
优点:
- ORM 自带预编译机制,屏蔽了 SQL 的拼接细节。
- 降低人为编码错误的风险。
注意:
- ORM 的原生语法是安全的,但一旦手写原生 SQL 或拼接字符串调用
.raw()
、.execute()
等方法,也可能引入漏洞。
3. 输入校验(Input Validation)
用途:
- 不是用于阻止注入,而是作为辅助手段减少异常输入。
- 例如只接受数字、邮箱、用户名等符合格式的内容。
限制:
- 不能依赖它来防注入,因为攻击者可以绕过前端验证,直接发包。
4. 最小权限原则(Least Privilege Principle)
实践:
- 数据库用户应只具备执行当前业务所需的权限,如只读、只写等。
- 禁止 Web 应用使用
root
或管理员账户连接数据库。
意义:
- 即便被注入成功,攻击者也难以造成更大破坏(如 DROP TABLE、修改数据等)。
5. 错误信息控制
做法:
- 不将数据库错误(如 SQL 语法错误、字段不存在等)直接返回给前端。
- 避免暴露表结构、字段名,为攻击者提供辅助信息。
6. Web 应用防火墙(WAF)
角色:
- 提供额外的一层防护,识别常见 SQL 注入 payload 并阻断请求。
- 并非替代手段,而是作为兜底机制。
批判性思考与误区警示:
- ❌ 拼接字符串+转义(如 mysql_real_escape_string)已过时:处理复杂嵌套 SQL、字符集时易出错,不应再依赖。
- ❌ 前端验证不可替代后端验证:攻击者可以跳过前端逻辑。
- ✅ 参数化是唯一可以完全防止注入的方式,其他手段都是辅助或事后防御。