正则表达式不能防止SQL注入,仅可用于前端提示或日志筛查;真正防护必须依赖mysqli::prepare或PDO::prepare参数化查询,并配合输入过滤与最小权限原则。
正则表达式不能防止 SQL 注入,它最多只能做前端提示或日志筛查——真正在数据库执行前拦截恶意输入,必须靠 mysqli::prepare 或 PDO::prepare。
攻击者早就不写 SELECT 了,改用 sel/**/ect、%27(URL 编码单引号)、UNI/**/ON、甚至双写绕过(SELESELECTCT)都能轻松跳过 /union|select|drop/i 这类规则。更麻烦的是,preg_replace 直接删掉匹配内容会破坏合法字段:用户昵称叫 “Union Jack” 就变成 “Jack”,而删掉 WHERE 后的空格还可能触发 MySQL strict mode 报错。
常见错误现象包括:
PREG_BACKTRACK_LIMIT_ERROR:超长输入+贪婪匹配(如 .*)导致 PCRE 回溯爆炸u 修饰符,preg_match 在 UTF-8 字符串里中途崩溃/i 本意是兼容,结果让 selECT 漏过;不如直接禁用该字段只在两类地方能用,且必须配合后端参数化查询:
' OR 1=1 --、连续 5 个以上括号 (((((、裸露分号结尾 ;
/(%27)|(')|(--)|(#)/,用于告警而非阻断推荐写法示例(PHP):
if (preg_match('/['";--=<>]|--|*//', $input)) { // 记录日志 + 前端提示,但不拒绝请求 error_log("Suspicious input: " . $input); echo "输入含非法符号,请检查";}
注意:['";--=] 里连字符 - 必须放最后,否则被解释为范围符;* 和 / 要转义。
把精力从“怎么写正则”转移到这三步上,防护效果远超任何字符串匹配:
mysqli::prepare 或 PDO::prepare,变量全用 ? 占位符filter_var($input, FILTER_SANITIZE_SPECIAL_CHARS)(PHP 8.1+ 推荐),或至少用 htmlspecialchars($input, ENT_QUOTES, 'UTF-8')
SELECT、INSERT,绝不要 FILE、EXECUTE 或 DROP
正则唯一不可替代的作用,是帮你发现异常输入模式;但它永远没法定义“合法 SQL”——比如 JSON 字段里嵌了 SQL 片段,或者 GraphQL 查询体混了原生语句,这种边界 case 只能靠协议层和权限层来兜底。