什么是 SQL 注入?
SQL 注入(SQL Injection) 是Web应用中最常见和危害极大的安全漏洞之一。攻击者通过在Web表单、URL参数、HTTP头等输入中注入恶意的SQL代码,诱使后台数据库执行非预期的SQL命令,从而达到非法获取、篡改、删除数据,甚至控制数据库服务器的目的。
SQL 注入的原理
多数Web系统会根据用户输入,拼接生成SQL查询语句。如果开发者未对输入内容做严格过滤和转义,攻击者就有机会插入恶意SQL片段,篡改原本的语句逻辑。
举例说明:
假设有如下代码用于用户登录验证:
# 不安全的拼接
sql = "SELECT * FROM users WHERE username = '%s' AND password = '%s'" % (username, password)
攻击者输入:
- username: admin
- password: ' OR '1'='1
最终SQL语句变为:
SELECT * FROM users WHERE username = 'admin' AND password = '' OR '1'='1'
由于 OR '1'='1' 总为真,数据库会返回所有数据,导致绕过认证。
SQL 注入的常见类型
- 联合注入(Union-based Injection)
通过
UNION 语句合并攻击者自定义查询,获取其他表的数据。
- 报错注入(Error-based Injection)
利用数据库报错信息泄露字段或表结构。
- 盲注(Blind Injection)
页面不返回具体报错和数据,攻击者通过判断页面响应内容或用延时语句推断数据库信息。例如
AND IF(condition, SLEEP(5), 0)。
- 堆叠注入(Stacked Queries)
支持多语句的数据库下,攻击者插入
; 追加执行多条SQL,实现如数据删除、管理员添加等破坏性操作。
SQL 注入的危害
- 绕过身份验证、登录系统
- 窃取敏感数据(如账户、密码、银行卡等)
- 删除/篡改数据库中的数据
- 破坏业务逻辑、持久化挂马
- 提权甚至入侵服务器
防御 SQL 注入的方法
-
使用预编译语句(Parameterized Query/Prepared Statement)
不拼接SQL字符串,将用户输入作为参数传递,开发语言或数据库驱动自动处理参数转义。
# Python 示例(以 sqlite3 为例)
cursor.execute('SELECT * FROM users WHERE username=? AND password=?', (username, password))
-
输入合法性校验
对所有用户输入做白名单校验(如用户名、ID只能为字母数字),拒绝异常字符。
-
最小化数据库权限
数据库账号原则上应只赋予必须权限(如 select/insert),不要用 root 或超级管理员账号连接数据库。
-
避免返回详细错误信息
生产环境关闭数据库错误详细输出,防止攻击者据此调整注入 payload。
-
及时升级用到的Web框架和数据库
使用主流Web框架并保持安全更新。
-
开启WAF(Web应用防火墙)过滤常见注入特征
增加安全防护层级。
检测方法
- 代码审计: 排查所有SQL拼接、动态生成SQL语句的地方
- 黑盒测试: 自动化工具(如sqlmap)或手工构造payload测试
- 概率特征: 输入
' OR '1'='1、' UNION SELECT ...等出现异常、返回多条数据或报错时,应高度警惕