不能仅用mysql_real_escape_string + mysql_query修补,因其对数字参数无效、无法防堆叠注入、依赖字符集一致且函数已废弃;必须改用禁用模拟预处理的PDO::prepare()等参数化方案。

直接替换 mysql_connect 和 mysql_query 不行,必须重写查询逻辑,否则只是把旧漏洞换了个函数名继续跑。
为什么不能简单用 mysql_real_escape_string + mysql_query 修修补补
这个组合看似能“转义”,但实际有多个失效场景:
- 它只对字符串类型生效,数字型参数(如
id=123)不加引号时,mysql_real_escape_string完全不处理,攻击者可直接注入123 OR 1=1 - 它无法防御堆叠查询(如
1; DROP TABLE users;),因为分号在转义后仍被数据库执行 - 它依赖正确的字符集设置(
mysql_set_charset),若连接层和表层字符集不一致,宽字节注入仍可绕过 -
mysql_*函数已在 PHP 7.0 中彻底移除,强行保留等于锁定版本、拒绝安全更新
PDO::prepare() 必须禁用模拟预处理
默认情况下,PDO 会启用 PDO::ATTR_EMULATE_PREPARES = true,即由 PHP 层“模拟”预处理——这会导致占位符被拼回 SQL 字符串后再发给 MySQL,等同于自己做字符串拼接,失去防注入意义。
正确做法是在创建 PDO 实例后立即关闭它:
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // 关键:强制交由 MySQL 服务端预处理
PDO::MYSQL_ATTR_MULTI_STATEMENTS => false, // 禁用多语句,防堆叠注入
]);
验证是否生效:执行 $pdo->getAttribute(PDO::ATTR_EMULATE_PREPARES) 应返回 false;再查 MySQL 的 SHOW STATUS LIKE 'Com_stmt_prepare',能看到计数增长,说明真正在用服务端预处理。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
批量替换时的三类常见语法陷阱
老旧代码里常出现以下结构,直接套用 prepare() 会报错或行为异常:
-
动态字段名/表名:如
"SELECT * FROM {$table} WHERE id = ?"—— 占位符不能用于标识符,必须白名单校验后硬拼,例如in_array($table, ['users', 'orders']) ?: die('非法表名'); -
动态
ORDER BY或LIMIT:如"ORDER BY {$sort} {$dir}"—— 同样不可参数化,需用枚举映射:$sort_map = ['name' => 'name', 'created_at' => 'created_at']; $dir = in_array($dir, ['ASC', 'DESC']) ? $dir : 'ASC'; -
IN 子句变长参数:如
"WHERE id IN (?) "无法匹配多个值 —— 要动态生成占位符:$ids = [1, 5, 9]; $placeholders = str_repeat('?,', count($ids) - 1) . '?'; $stmt = $pdo->prepare("SELECT * FROM users WHERE id IN ($placeholders)"); $stmt->execute($ids);
连接和错误处理必须同步重构
旧代码常用 @mysql_query() 抑制错误,掩盖问题。PDO 必须显式设错处理模式,否则 prepare() 失败会静默返回 false,后续 execute() 直接 fatal error:
- 务必设置
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,让所有错误抛出异常,便于定位哪条 SQL 出了问题 - 不要用
try/catch包裹整个 DAO 类,而应在每个具体操作(如登录、列表、更新)里捕获并记录PDOException,同时向用户返回泛化提示(如“操作失败,请稍后重试”) - 生产环境禁用
PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING,避免数据库结构泄露到前端
真正难的不是写对一条 prepare,而是确保所有分支路径(包括条件查询、空值处理、事务回滚)都走同一套参数化逻辑。漏掉一个 mysql_query("UPDATE ... SET x='$_POST[x]'"),整套重构就归零。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










