addslashes无法防止SQL注入,因其仅转义'、"、\和NUL,不理解SQL语法结构,对数字位置、标识符、宽字节绕过等场景完全无效;预编译语句才是根本解决方案。

addslashes只转义几个字符,根本不管SQL语法结构
addslashes 只对 '、"、\ 和 NUL 字节加反斜杠,它不理解 SQL 是什么,也不区分数字、字符串、标识符或关键字。比如你拼接 WHERE id = $_GET['id'](没引号),攻击者传 id=1 OR 1=1,addslashes 完全不动这个输入——因为里面没有要转义的字符,但 SQL 已经被篡改了。
宽字节编码下,转义会被“吃掉”
当 MySQL 连接字符集是 gbk,而 PHP 没调用 mysqli_set_charset($conn, 'gbk') 或执行 SET NAMES gbk 时,addslashes 仍按单字节逻辑处理:%df%5c(即 %df\)会被 MySQL 解码成一个汉字,后面的 %27(单引号)就裸露出来了。结果是 ' 没被转义,注入成功。这不是你漏写了函数,是机制层面的失效。
它对非字符串位置完全无效
以下这些场景,addslashes 一概无能为力:
-
ORDER BY $_GET['sort']—— 表名、列名、排序方向属于 SQL 标识符,不能加引号,也不能参数化 -
LIMIT $_GET['offset'], $_GET['count']—— 数字位置不走字符串解析,转义毫无意义 -
UNION SELECT ...或; DROP TABLE users—— 分号、括号、注释符(--、#)都不在addslashes的处理列表里
类型混淆和静默失败更危险
有人图省事写 WHERE id = " . (int)$_GET['id'],这确实能挡注入,但会把 id=abc 变成 0,查不到数据却没报错,掩盖了业务异常。而 addslashes('abc') 返回原样,拼进 SQL 后可能直接报错或返回空结果,问题反而暴露得更早——但这不是安全,只是“碰巧没炸”。
立即学习“PHP免费学习笔记(深入)”;
真正卡住的地方在于:预编译语句(PDO::prepare / mysqli_prepare)让数据库在解析阶段就固定 SQL 结构,后续 bind 的值永远只是数据,不会参与语法分析。而 addslashes 始终在 PHP 层做字符串修补,它面对的是已经破碎的抽象边界。



















