SQL注入中,攻击者常在参数后追加--或#来注释掉原语句后续条件,从而改变查询逻辑。除了写代码时采用参数化查询,我们还可以从数据库解析器层面着手,让解析器遇到异常注释时直接抛出异常,而不是静默忽略,以此阻断注入路径。

注释符注入的基本原理
在MySQL中,#和-- 后面内容会被当作注释。例如登录语句拼接为:
SELECT * FROM user WHERE name='admin' AND pwd='xxx' -- 攻击者输入 pwd 为: x' OR 1=1 # -- 实际执行: SELECT * FROM user WHERE name='admin' AND pwd='x' OR 1=1 #'
这样密码校验被注释掉,条件恒真。如果数据库解析器对畸形注释不报错,攻击就成功了。
配置解析器忽略异常注释的思路
我们要让数据库在收到含异常注释的SQL时直接返回语法错误。以MySQL为例,可通过服务端参数与代理层配合实现。
1. 使用严格SQL模式
开启STRICT_ALL_TABLES与ANSI_QUOTES可减少宽松解析,但对注释不一定拦截。更有效的做法是在应用与数据库间加一层SQL防火墙。
2. 自写解析校验中间件
在Java应用中,可先对传入SQL做轻量校验,发现单引号后紧接--或#且不在字符串内时拒绝执行:
public static boolean hasAbnormalComment(String sql) {
// 简单判断是否存在 -- 或 # 且前面有引号闭合异常
if (sql.contains("--") || sql.contains("#")) {
// 实际应使用语法树解析,这里仅示例
return true;
}
return false;
}
3. 数据库侧参数限制
PostgreSQL可在会话中设置standard_conforming_strings并配合pg_stat_statements监控异常。MySQL可修改my.cnf:
[mysqld] sql_mode=STRICT_ALL_TABLES,NO_AUTO_CREATE_USER # 配合防火墙插件拦截含单行注释的非法请求
推荐的综合防御表
| 措施 | 作用 | 层面 |
|---|---|---|
| 参数化查询 | 彻底分离代码与数据 | 代码 |
| 输入白名单 | 限制特殊字符 | 应用 |
| 解析器异常注释报错 | 阻断畸形SQL执行 | 数据库/中间件 |
代码示例:Python中预处理拦截
下面代码在执行前检查注释符并抛错:
def safe_query(conn, sql):
if '--' in sql or '#' in sql:
raise ValueError('SQL contains abnormal comment')
cursor = conn.cursor()
cursor.execute(sql)
return cursor.fetchall()
需要注意,以上校验不能替代参数化。正确写法应使用占位符:
cursor.execute('SELECT * FROM user WHERE name=%s', (user_input,))
小结
让数据库解析器对异常注释报错,是纵深防御的一环。开发仍应以参数化查询为主,配合输入校验与解析层拦截,才能有效抵御利用--或#的SQL注入。