如何防范存储型SQL注入_对存入数据库的字段进行转义

1次阅读

应使用参数化查询而非 mysql_real_escape_string 或 addslashes,因其彻底分离 SQL 结构与数据,避免宽字节绕过及字符集依赖问题;ORM 中需警惕原生 SQL 片段拼接,JSON/NoSQL 存储不改变 SQL 注入防护本质。

如何防范存储型 SQL 注入_对存入数据库的字段进行转义

存入数据库前用 mysql_real_escape_string 还是 addslashes

别用这两个。它们只处理单引号、反斜杠等有限字符,且依赖当前连接的字符集;如果数据库连接用的是 gbklatin1,攻击者可以用宽字节绕过,addslashes 完全无效。mysql_real_escape_string 已在 PHP 7.0 中废弃,且仅适用于旧版 MySQL 扩展(mysql_*),不兼容 mysqliPDO

真正该做的是:** 用参数化查询(Prepared Statement)替代字符串拼接 **。它把 SQL 结构和数据彻底分离,数据库引擎在解析阶段就确定字段类型和边界,根本不会把用户输入当 SQL 代码执行。

  • PDO 示例:$stmt = $pdo->prepare("INSERT INTO users (name) VALUES (?)"); $stmt->execute([$user_input]);
  • mysqli 示例:$stmt = $mysqli->prepare("SELECT * FROM posts WHERE id = ?"); $stmt->bind_param("i", $id); $stmt->execute();
  • 所有占位符(? 或命名参数如 :name)都由驱动层原生处理,无需手动转义

为什么不能靠“入库前过滤”防存储型 SQL 注入?

因为过滤逻辑容易滞后、不统一、不可靠。比如你写了个 escape_sql 函数,但同事在另一个模块直接拼接了 "UPDATE logs SET msg = '" . $_POST['msg'] . "'";或者过滤只做了 HTML 实体编码(htmlspecialchars),对 SQL 完全无效;又或者用了 stripslashes 反向清理,反而破坏正常数据。

更关键的是:** 同一段数据可能被用于不同上下文 **——今天插进 MySQL,明天导出到 CSV,后天拼进 shell 命令。靠“入库前一刀切转义”,等于把所有数据都按 SQL 上下文预设,后续其他用途反而要额外反转,极易出错。

  • 存储型注入的核心风险不在“存”,而在“取出来再拼 SQL 时没防护”
  • 所以防护点必须落在每次查询构造环节,而不是入库那一刻
  • 数据库字段类型(如 VARCHAR(255))本身不提供任何注入防护能力

ORM 框架里怎么避免手写 SQL 导致的漏洞?

主流 ORM(Laravel Eloquent、Django ORM、SQLAlchemy)默认使用参数化查询,但陷阱常出现在“原生 SQL 片段”或“动态查询构建”中。比如 Laravel 的 whereRaw()、Django 的 extra()raw()、SQLAlchemy 的 text()

这些方法一旦拼接用户输入,就等于退回到裸 SQL 风险区。必须显式传参,不能字符串插值。

  • ❌ 错误:->whereRaw("name LIKE '%{$_GET['q']}%'")
  • ✅ 正确:->whereRaw("name LIKE ?", ["%{$_GET['q']}%"])(Laravel)
  • ✅ 正确:session.execute(text("SELECT * FROM users WHERE name = :name"), {"name": name})(SQLAlchemy)
  • 注意:即使 ORM 提供了 quote()escape_string() 方法,也别用——它们只是模拟转义,不如参数化可靠

JSON 字段或 NoSQL 存储能绕过 SQL 注入防护吗?

不能。SQL 注入只发生在 SQL 查询执行环节,和你存的是纯文本、JSON 还是 BSON 无关。如果你从 MongoDB 取出一个 JSON 字符串,再把它拼进 MySQL 的 INSERT 语句里,照样会触发注入。

真正的分界线是:** 数据是否经过参数化机制进入查询 **。哪怕你用 Redis 存用户输入,只要之后用 redis.get(……) 拿出来,再塞进 "SELECT * FROM x WHERE id = " . $id,风险就存在。

  • NoSQL 也有自己的注入问题(如 MongoDB 的 $ne$regex 操作符滥用),但那属于另一类漏洞,不能误以为“不用 SQL 就安全”
  • JSON 字段内容若后续被 json_decode() 后拼进 SQL,仍需走参数化流程
  • 最稳妥的做法:所有外部输入,只要参与 SQL 构造,一律走绑定参数,不管它中间经过多少次存储或格式转换

事情说清了就结束。真正难的不是记住哪个函数该用,而是团队里每个人在写 WHERE 条件、写 ORDER BY 字段、甚至写迁移脚本里的 INSERT 时,都下意识拒绝字符串拼接。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-23发表,共计1942字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources