addslashes不能防住所有SQL注入,根本原因在于它不感知SQL语法上下文和数据库字符集,对数字型参数完全无效,且易受宽字节注入绕过;预编译+参数绑定才是可靠解法。
addslashes 不能防住所有 SQL 注入,根本原因在于它不感知 SQL 语法上下文和数据库字符集
addslashes 对数字型参数完全无效
当 SQL 中的字段是数字类型(如
),却用字符串拼接方式写成
,
就毫无意义。攻击者直接传
,不会触发任何单引号,转义逻辑压根不生效。
典型场景:
—— 这里
没有引号包裹,
加的反斜杠反而可能破坏整数解析
正确做法:数字参数必须强制类型转换(如
)或统一走参数绑定
隐患点:很多老代码把所有输入“习惯性”过一遍
,误以为一劳永逸
宽字节注入可绕过 addslashes
在 MySQL 使用
、
等多字节编码时,
的转义会被吃掉一个字节。例如输入
(
是 GBK 下的合法首字节),MySQL 会将
(即
)识别为一个汉字,导致后续的
(单引号)逃逸出来。
防SQL注入的php类库
防SQL注入的php类库
下载
触发条件:PHP 连接未显式设置字符集(如
),且 MySQL 配置为
能规避此问题,因为它依赖实际连接的字符集做转义;但
完全无视这点
现代 PHP 默认用
,但遗留系统或中间件仍可能降级到 GBK
预编译 + 参数绑定才是可靠解法
预编译的本质是把 SQL 结构和数据分离传输:先发模板(如
),再单独发参数值。MySQL 在服务端解析时,参数永远作为“数据”处理,不会参与语法解析。
MySQLi 示例:
PDO 示例:
注意:
必须设为
,否则 PDO 会在 PHP 层模拟拼接,退化为字符串替换
无法参数化的部分(如表名、ORDER BY 字段)必须用白名单校验,不能靠任何转义函数
真正容易被忽略的是:预编译只保值,不保结构。哪怕用了
,如果把用户输入拼进表名、字段名或
子句里,照样中招。防御边界必须划清楚——哪些能参数化,哪些只能白名单,这个判断比写几行转义代码难得多。
id = ?"id = '$id'"addslashesid=1 OR 1=1$sql = "SELECT * FROM users WHERE id = $id";$idaddslashes(int)$idaddslashesGBKGB2312addslashes%df%27%df%df%5c%df\%27SET NAMES gbkcharacter_set_client=gbkmysqli_real_escape_stringaddslashesutf8mb4SELECT * FROM users WHERE username = ?$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ?"); $stmt->bind_param("s", $_GET['username']); $stmt->execute();$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?"); $stmt->execute([$_GET['username']]);PDO::ATTR_EMULATE_PREPARESfalseprepareUNION SELECT