白名单校验必须在后端做,前端校验无效;需在node.js路由、java controller、python视图等服务端层精确到字段级校验,如status仅允许['active','inactive','pending'],并统一处理空格、编码、unicode等绕过手段。

SQL注入的白名单校验该在哪一层做
必须在后端做,前端校验形同虚设。用户可以绕过任何前端限制直接发请求,fetch、cURL、甚至浏览器开发者工具都能改参数。白名单逻辑如果只写在 JavaScript 里,等于没设防。
常见错误现象:WHERE name = '${req.query.name}' 拼接 SQL;或用 mysql.escape() 但没过滤特殊字符组合(如 admin'--)。
- 白名单校验位置:Node.js 的路由处理函数、Java 的 Controller 层、Python 的 Flask/Django 视图中
- 不校验长度、不校验格式、只检查“是否包含关键词”的黑名单方式,基本无效
- 白名单要精确到字段级:比如
status参数只允许['active', 'inactive', 'pending'],不能只说“只能是字符串”
如何定义和维护白名单值
白名单不是写死在 if 判断里的字符串数组,而是可配置、可验证、有明确边界的枚举集合。
使用场景:查询状态、排序字段、分页大小、操作类型等有限取值参数。
参数差异:sort 字段允许 ['created_at', 'updated_at', 'score'],但不允许 'id ASC, email DESC' 这类带语法的输入;limit 必须转为整数并限制范围(如 1–100),不能直接拼进 SQL。
- 用常量对象或 enum 类型定义白名单,例如
const VALID_SORT_FIELDS = { created_at: true, updated_at: true } - 校验时用
Object.prototype.hasOwnProperty.call(VALID_SORT_FIELDS, input),避免原型污染干扰 - 数据库列名、表名这类元数据严禁由用户输入决定;真有动态需求,走预定义映射表,而不是字符串拼接
为什么不能只靠参数化查询就高枕无忧
参数化查询(如 query('SELECT * FROM users WHERE id = ?', [id]))能防绝大多数注入,但对“结构动态”场景完全失效——比如 ORDER BY ? 中的问号无法绑定列名,TABLE ? 更不行。
性能 / 兼容性影响:白名单校验本身开销极小,但若每次请求都读配置文件或查数据库判断合法性,反而引入延迟和单点故障。
- 列名、表名、关键字(
ASC/DESC)必须走白名单,不能进参数化占位符 - 避免用
eval、Function、new Function动态构造 SQL 片段 - ORM 如 Sequelize 的
order: [['created_at', 'DESC']]是安全的,但order: req.query.order就是漏洞
容易被忽略的边界情况
白名单校验不是加个 if (['a','b'].includes(x)) 就完事。大小写、空格、编码、多字节字符、Unicode 归一化都会让校验失效。
常见错误现象:'ACTIVE '(带空格)、'active%20'(URL 编码)、'active'(全角字母)绕过校验后进入 SQL。
- 校验前统一
.trim()、.toLowerCase()、.normalize('NFC') - 拒绝所有非 ASCII 字母数字下划线的字符,除非业务明确需要(如多语言国家代码)
- 日志里记录被拒绝的原始参数值,方便发现绕过尝试;但别把完整 SQL 或敏感字段打出来
白名单规则越细,覆盖场景越多,就越难被绕过;但一旦漏掉一个合法值,功能就挂。所以得把每个字段的允许值写进单元测试,而不是靠人眼 review。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










