是的,_作为SQL LIKE单字符通配符,配合错误回显可暴力猜解系统表字段(如version)以推断数据库版本;需通过转义或参数化查询使其失效,而非仅依赖前端过滤或关闭错误提示。

SQL注入里_通配符会意外暴露数据库版本?
是的,_ 在 SQL 的 LIKE 查询中是单字符通配符,攻击者用它配合已知表名或错误回显,可能暴力猜出系统表字段(比如 version、@@version),进而推断数据库类型和版本。这不是直接“泄露”,而是通过响应差异(如查询是否报错、返回行数变化)间接确认——尤其在未关闭错误提示、又没做输入过滤的旧系统里很常见。
- 典型场景:用户输入被拼进
WHERE name LIKE '%{user_input}%',而你没转义_和% -
_不需要开启任何特殊模式,在 MySQL、PostgreSQL、SQL Server、Oracle 中默认生效 - 只要后端把数据库错误原样返回(比如
Unknown column 'v_r' in 'where clause'),攻击者就能靠下划线试探字段名
怎么安全地处理带_的用户输入?
核心不是禁用 _,而是让它的语义失效——要么转义,要么改用参数化查询彻底隔离数据与逻辑。
- 如果必须用
LIKE且无法改写为参数化(比如动态模糊字段名),就对用户输入里的_和%做转义,并在LIKE子句里声明转义符:WHERE name LIKE '%_abc%' ESCAPE '' - 更推荐:改用预编译参数(
PreparedStatementin Java /pg_query_paramsin PHP /cursor.execute()with tuple in Python)——这时_就只是普通字符,根本不会被当通配符解析 - 别信“前端过滤”或“黑名单替换”,
\_、_、URL 编码后的%5F都可能绕过
隐藏数据库标识不只是关错误提示
关掉 show_errors 或 display_errors 只是第一步。很多框架和中间件会在 HTTP 头、响应体、甚至注释里悄悄带上数据库指纹。
- 检查响应头:
Server、X-Powered-By是否暴露了 MySQL/PostgreSQL 版本 - 确认 Web 服务器(Nginx/Apache)没在错误页模板里硬编码数据库信息
- ORM 日志若开启 debug 模式,可能打印原始 SQL 和驱动版本,别让它上生产
- 某些数据库(如 PostgreSQL)的
pg_version()函数可通过子查询触发,即使没回显,也能靠布尔盲注+_猜解
为什么只转义_还不够?
因为攻击者不只靠 _。一旦你允许任意字符串进 LIKE,他们还能用 % 构造全表扫描、用括号改变逻辑优先级、甚至嵌套子查询。真正的防护边界不在字符层面,而在执行上下文层面。
- 允许模糊搜索 ≠ 允许任意 SQL 片段;应限定字段范围(如只允许查
title或content),而不是拼接用户给的字段名 - 如果业务真要支持“类似 Google 的搜索语法”,就用专用库(如 Elasticsearch、Meilisearch),别手写 SQL 解析器
- 最常被忽略的一点:即便用了参数化,若把用户输入直接用于
ORDER BY或GROUP BY,照样能注入——这些地方不接受参数占位符
真正难防的不是某个字符,而是把用户输入当作代码一部分来执行的惯性思维。哪怕你把 _ 转义得再严,只要还拼 SQL 字符串,就永远留着缝。










