php 5.6项目修复sql注入漏洞,必须先确认mysqli扩展已启用且正确配置字符集,再严格使用预处理语句绑定参数,禁用mysql_*函数,动态标识符须白名单校验。

直接上结论:别信“看起来安全”的拼接,先全局搜 mysql_query(、mysqli_query( 和字符串拼接模式,再逐个验证是否用了预处理——PHP 5.6 项目里,90% 的 SQL 注入漏洞藏在没启用 mysqli 扩展却硬改 prepare() 的死代码里。
grep 出所有可疑 SQL 拼接点
Legacy 项目里,注入点往往不是明面上的 ' OR 1=1,而是分散在日志记录、搜索条件、导出语句等边缘逻辑中。别靠肉眼翻,用命令快速定位:
- 查所有
mysql_query(调用:grep -r "mysql_query(" . --include="*.php"—— 这类函数已废弃,且根本不支持预处理,必须全部替换 - 查字符串拼接 SQL:
grep -r "'.*\$_" . --include="*.php" | grep -E "(query|execute|fetch)",重点盯$_GET、$_POST、$_COOKIE直接进 SQL 的行 - 查 MyBatis 风格的
${占位:grep -r "${[a-zA-Z0-9_]+}" . --include="*.php",哪怕项目没用 MyBatis,也有人手写类似逻辑
确认 mysqli 扩展是否真可用
很多老项目注释里写着“已升级预处理”,结果运行时 mysqli_prepare() 返回 false 却没报错——因为扩展根本没加载。CLI 和 Web 环境的 php.ini 常不一致,必须双端验证:
- Web 端:建一个
info.php,内容为<?php phpinfo(); ?>,浏览器打开后搜mysqli,看“enabled”是否为 yes - CLI 端:执行
php -m | grep mysqli,或运行脚本:var_dump(extension_loaded('mysqli')); - 常见坑:
mysql扩展开着 ≠mysqli开着;某些一键环境默认只开mysql;php.ini里写的是extension=mysqli.so(Linux)或extension=php_mysqli.dll(Windows),名字写错就白配
检查预处理是否被模拟或绕过
即使 mysqli_prepare() 调用成功,也不代表安全——如果底层是模拟预处理(emulated prepares),它只是客户端拼字符串,和手拼没区别。PHP 5.6 默认不开启模拟,但旧配置可能残留:
- 查
mysqli连接后是否调了mysqli_set_charset($conn, 'utf8mb4'):没设字符集时,gbk库下%df%5c宽字节注入会复活,addslashes()彻底失效 - 查
bind_param()是否传了引用:PHP 5.6 必须写$stmt->bind_param('s', $username),漏掉&或类型码写成'str'会导致绑定失败但无提示 - 查有没有混用:比如先
mysqli_real_escape_string()再bind_param(),双重转义可能截断字段值,尤其对varchar(32)类短字段
动态标识符(表名/排序字段)必须白名单硬控
占位符 ? 和 :name 只能用于数据值,不能用于表名、列名、ORDER BY 字段——这是预处理的硬限制,不是疏忽。很多修复者卡在这一步,以为加了 prepare() 就万事大吉:
-
ORDER BY动态字段:必须白名单校验,例如$sort = in_array($_GET['sort'], ['id', 'name', 'created_at']) ? $_GET['sort'] : 'id';,然后拼进 SQL:"ORDER BY {$sort} DESC" - 动态表名:禁止从 request 直取,应映射为键值对:
$tables = ['user' => 'users', 'log' => 'admin_logs']; $table = $tables[$_GET['type']] ?? 'users'; - 禁止用
filter_var($input, FILTER_SANITIZE_STRING)处理字段名——它只删 HTML 标签,不防users; DROP TABLE users
最易被忽略的是字符集与预处理的耦合:mysqli_set_charset() 必须在 mysqli_prepare() 之前调用,否则宽字节注入在 gbk 库下仍可触发;而 PDO 用户常忘了关 PDO::ATTR_EMULATE_PREPARES,导致 prepare 变成假安全。这些细节不写进日志、不抛异常,只有拿 sqlmap 扫一遍才能暴露。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











