php函数怎么piso处理特殊符号_用addslashes防注入转义【技巧】

1次阅读

addslashes 不是防 sql 注入的可靠方法,它仅简单转义特定字符而不感知 sql 语义,无法防御宽字节截断、十六进制绕过等攻击,且在 pdo 真实预处理下会导致双重转义;正确方案是 pdo 预处理绑定参数并禁用模拟预处理。

php函数怎么piso处理特殊符号_用addslashes防注入转义【技巧】

直接说结论:addslashes 不是防 SQL 注入的可靠方法,它不能替代预处理(PDO::preparemysqli_prepare),且对 PDO 的 PDO::ATTR_EMULATE_PREPARES = false 场景完全无效。

为什么 addslashes 不能防注入?

它只是在单引号、双引号、反斜杠和 NULL 字节前加反斜杠,不感知 SQL 语义,也不处理十六进制编码、宽字节绕过、多字节字符集(如 gbk)下的截断问题。攻击者可绕过方式包括:

  • 使用 %df%27(gbk 双字节截断)触发引号逃逸
  • 0x756e696f6e2073656c656374 十六进制绕过单引号过滤
  • PDO 开启真实预处理时,addslashes 会把参数里的反斜杠原样送入 SQL,导致数据被错误转义(比如存入 O'Reilly 变成 O'Reilly

正确做法:用 PDO 预处理 + 绑定参数

这才是真正切断 SQL 逻辑与数据的方案。关键点:

  • 必须设置 PDO::ATTR_EMULATE_PREPARES = false(禁用模拟预处理)
  • 参数一律用 bindValuebindParam,不要拼接字符串
  • 字符集要在 DSN 中指定,例如 charset=utf8mb4,不能靠 set names
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', $user, $pass, [     PDO::ATTR_EMULATE_PREPARES => false,     PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); $stmt = $pdo->prepare('SELECT * FROM users WHERE name = ? AND status = ?'); $stmt->bindValue(1, $_GET['name'], PDO::PARAM_STR); $stmt->bindValue(2, $_GET['status'], PDO::PARAM_INT); $stmt->execute();

什么时候能用 addslashes

仅限极少数遗留场景,且必须满足全部条件:

立即学习PHP免费学习笔记(深入)”;

  • 数据库字符集明确为 latin1 或严格 utf8(非 utf8mb4
  • 确认未开启 magic_quotes_gpcphp 5.4+ 已移除,但老系统可能有自定义兼容层)
  • 仅用于生成日志、调试输出等非 SQL 上下文的简单转义
  • 绝对不用在 mysqli_real_escape_string 已可用的情况下替代它

哪怕满足以上,也建议改用 mysqli_real_escape_string($link, $str)——它依赖当前连接的字符集,比 addslashes 安全得多,但仍不如预处理。

addslashes 和特殊符号 _ 的关系?

它对下划线 _ 完全不做处理——_ 在 SQL 中是通配符(LIKE 模式匹配),但 addslashes 不管这个。如果你要安全地做模糊查询,得手动转义 _%,并指定 ESCAPE 字符:

$search = str_replace(['_', '%'], ['_', '%'], $_GET['q']); $stmt = $pdo->prepare("SELECT * FROM posts WHERE title LIKE ? ESCAPE ''"); $stmt->execute(["%{$search}%"]);

注意:这里的 是 SQL 的转义符,不是 PHP 的;PDO 绑定后不会二次解析,所以必须由你控制好转义逻辑。

真正麻烦的地方不在函数怎么写,而在很多人把「看起来没报错」当成「防住了」——只要没走预处理,SQL 注入风险就一直存在,哪怕用了 addslasheshtmlspecialchars 或正则过滤。

text=ZqhQzanResources