用户提交漏洞的本质,是把“用户能输入的内容”错误地当成了“系统可以信任的指令”。绝大多数注入风险并不是因为攻击者技术多高明,而是接收端没有对输入数据的类型、长度、编码和上下文做严格约束。要规避恶意注入,不能只靠前端校验或简单的关键词过滤,必须从数据入口、输出渲染、存储结构、权限边界四个层面同时设防。下面直接拆解具体的攻击路径和对应的防护方法。
先分清三类最常见的用户提交注入场景
第一类是SQL注入,用户提交的内容被拼接进数据库查询语句。比如登录表单里输入 ' or '1'='1 ,如果后端直接写成 SELECT * FROM users WHERE name='$input' ,整个查询条件就会被改写。第二类是跨站脚本注入(XSS),用户提交的HTML或JavaScript代码被原样输出到页面,其他用户打开页面时脚本在浏览器中执行。第三类是命令注入和模板注入,用户输入进入系统命令、文件路径、模板引擎或反序列化过程,造成服务器端代码执行。三类问题的共同点是:数据被当成代码执行了。
参数化查询是防SQL注入的第一道硬门槛
不要用字符串拼接的方式构造SQL语句,无论拼接前做了多少转义和过滤,都容易遗漏边界情况。正确做法是使用预编译语句和绑定参数,让数据库明确区分“SQL结构”和“数据值”。以PHP的PDO为例:
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $userInput]);
这里 :email 是占位符,用户输入只作为数据值传入,数据库不会解析其中的SQL关键字。Java的PreparedStatement、Python的cursor参数化查询、Go的database/sql占位符,原理完全一致。如果项目里存在大量拼接SQL的历史代码,优先把增删改查全部改成参数化形式,这比加过滤函数可靠得多。
白名单校验永远优先于黑名单过滤
用户提交的字段如果本来就有固定取值范围,比如性别、状态、排序方向、分页大小,直接用白名单判断。排序参数只允许 asc 和 desc ,状态只允许 0 或 1 ,分页大小只允许整数且在1到100之间。白名单的优点是未知输入默认拒绝,不会因为攻击者换用新的编码方式或绕过技巧而失效。黑名单过滤则相反,你封了 script ,攻击者可以用 scr