中间件无法防止sql注入,真正有效的是参数化查询与白名单校验组合;它仅能辅助过滤畸形输入、关键词拦截、日志脱敏等,而漏洞根源在数据库调用时的字符串拼接。

中间件本身不能防止SQL注入,它不参与SQL构造过程,也拦不住拼接行为——真正起作用的是参数化查询 + 白名单校验的组合,中间件顶多做前置格式过滤或日志脱敏。
为什么校验中间件对SQL注入基本无效
koa-router 或 express-validator 这类中间件运行在路由层,只检查 req.query、req.body 的结构和格式,比如判断 id 是否为数字、email 是否含 @。但它完全不知道后续代码会不会把 req.query.sort 拼进 ORDER BY ${req.query.sort} 里。
- 攻击者传入
name=1%00或id=1.5,校验可能放行(看起来像合法数字),但后续parseInt(req.query.id)返回NaN,一拼接就出问题 - 校验中间件无法识别
"admin' -- "是不是会被塞进WHERE name = '" + name + "' - ORM 的
.where({ name: req.query.name })是安全的,但一旦写成.where("name = '" + req.query.name + "'"),校验再严也没用
中间件能做的有限但实用的事
它不该承担“防注入”主责,但可以在关键位置补位:过滤明显畸形输入、统一清洗、阻断高危关键词(仅限非业务字段)、脱敏日志输出。
- 对搜索类接口的
q参数,可用正则快速拒绝含UNION、SELECT、information_schema的请求(注意大小写和编码绕过,仅作辅助) - 自动
trim()字符串、转义 HTML 实体(防 XSS,非 SQL 注入)、限制长度(如q不超过 200 字符) - 对用户名等业务字段,用白名单正则约束:
^[a-zA-Z0-9_\u4e00-\u9fa5]{2,20}$,比放任任意字符安全得多 - 日志中记录前必须清洗:
logger.info(`Search for ${sanitizedQuery}`, { ip: req.ip }),绝不能记{ rawQuery: req.query.q }
真正该加固的环节不在中间件里
SQL 注入漏洞不出现在请求入口,而出现在数据库调用那一行。中间件再完善,只要有一处 query(`SELECT * FROM users WHERE id = ${req.query.id}`),整套防护就失效。
-
mysql2必须用数组传参:db.query('SELECT * FROM users WHERE id = ?', [req.query.id]),哪怕只有一个值 - 表名、字段名、
ORDER BY子句无法参数化,必须硬编码或白名单映射:const validSort = { created: 'created_at', name: 'user_name' }; const field = validSort[req.query.sort] || 'created_at'; - 所有
catch块禁止透出error.sql或error.sqlState,这些字段可能含原始恶意 SQL - ORM 如 Sequelize 的
raw()、literal()方法会绕过参数化,必须单独审计
最容易被忽略的是错误响应和日志——它们往往不走中间件链,却直接暴露原始 SQL 和结构信息。防御不是加一层中间件就完事,而是确保从 req 到 query() 执行之间,没有一行字符串拼接、没有一处白名单遗漏、没有一个分支忘记脱敏。











