前端校验对SQL注入防护完全无效,因所有前端逻辑均可被绕过;真正有效的是后端参数化查询切断拼接环节,并对动态结构(如表名、排序字段)实施白名单校验。

前端校验对 SQL 注入防护完全无效,它既不参与数据库查询构造,也无法阻止攻击者绕过——真正起作用的只有后端的参数化查询和输入白名单校验。
为什么禁用 JS 就能直接绕过所有前端校验
浏览器里删掉 disabled、改掉 maxlength、清空 pattern 属性,甚至直接用 curl 发请求,都不需要任何技术门槛。这些操作跳过了整个 DOM 和事件监听逻辑,后端收到的仍是原始恶意字符串。
-
curl -X POST /login -d "username=admin'--&password=123"—— 前端 JS 根本没机会运行 - DevTools 修改
<input type="hidden" name="role" value="user">→ 改成"admin"后提交 - React/Vue 应用中用控制台执行
vm.$data.username = "admin' OR 1=1 --"再触发 submit - 旧接口、批量导入入口、URL 参数(如
?id=1' UNION SELECT ...)往往根本没套前端校验
为什么正则过滤或转义在后端眼里毫无意义
前端做的 replace(/'/g, "''") 或 encodeURIComponent() 只是改了字符串内容,数据库解析器根本看不到这些操作。后端如果还是用字符串拼接,那传过来的 "admin''--" 依然会变成 WHERE name = 'admin''--',注释符照常生效。
- 用户输入
admin%27--(URL 编码后的单引号+注释),前端没解码就过滤,漏掉 - Unicode 变体如
String.fromCharCode(8217)(中文右单引号)逃过 ASCII 正则 -
mysql_real_escape_string()在宽字节场景下会被绕过,addslashes()更是形同虚设 - 哪怕前端把
SELECT全替换成空,攻击者用SeLeCt、/**/SELECT/**/或分块编码照样过
哪些后端写法看似安全实则高危
很多开发者误以为用了“某种处理”就安全了,但只要输入最终进了拼接字符串,风险就始终存在。关键不是有没有处理,而是有没有切断拼接环节。
立即学习“前端免费学习笔记(深入)”;
-
db.query("SELECT * FROM users WHERE id = " + req.query.id)—— 直接裸奔 -
client.query(`SELECT * FROM ${tableName}`)—— 表名无法参数化,必须白名单 -
User.objects.extra(where=["name = '" + name + "'"])—— Django ORM 的陷阱 -
db.session.execute(f"UPDATE logs SET status = '{status}'")—— f-string = 拼接 = 注入 -
PreparedStatement却用executeQuery("SELECT ... WHERE x = " + input)—— 忘了传参,占位符白加
真正有效的防护必须落在后端且不可绕过
参数化查询不是加个问号就行,而是要确保数据库驱动把值当纯数据送进去;动态结构(如 ORDER BY 字段、表名)不能参数化,就必须用严格白名单映射;所有输入源(req.query、req.body、req.headers、req.cookies)都得走同一套校验逻辑。
- 数字型字段必须强转并捕获异常,比如
Long.parseLong(req.query.id) - 排序字段只允许映射到预定义集合:
sortMap.get("created_at") → "created_time DESC" - LIKE 模糊匹配要用
CONCAT('%', ?, '%'),而不是"'%"+input+"%'" - 日志记录前必须脱敏,否则未处理的
req.query.q可能引发日志注入 - 数据库账号禁用
DROP、CREATE、EXECUTE权限,最小权限兜底
最容易被忽略的是那些“不能参数化”的地方:动态表名、ORDER BY、LIMIT、GROUP BY 字段——它们不在占位符支持范围内,一旦拼接,就是高危开口。
















