PHP中SQL注入漏洞不能靠升级PHP版本修复,必须从代码层切断用户输入参与SQL语法构造的路径,核心是让数据和指令彻底分离,所有外部输入都不能直接拼进SQL字符串,必须使用PDO或MySQLi预处理语句全程绑定全部变量,禁用模拟预处理,数字与字符参数严格校验类型,动态结构(如表名、排序字段)须白名单控制,生产环境关闭错误回显并统一捕获异常。

PHP中SQL注入漏洞不能靠升级PHP版本修复,必须从代码层切断用户输入参与SQL语法构造的路径。核心是让数据和指令彻底分离,所有外部输入都不能直接拼进SQL字符串。
用预处理语句绑定全部变量
这是最根本、最可靠的修复方式。PDO或MySQLi的prepare+execute/bind_param必须全程覆盖,不能只写占位符却不绑定:
- ✅ 正确写法:所有参数都走绑定,包括数字、字符串、状态值
- ❌ 错误写法:SQL里混用占位符和字符串拼接,比如
"WHERE id = :id AND name = '".$_POST['name']."'" - ⚠️ 注意PDO默认启用模拟预处理(
PDO::ATTR_EMULATE_PREPARES = true),必须显式关闭:new PDO($dsn, $u, $p, [PDO::ATTR_EMULATE_PREPARES => false])
数字和字符参数必须分类校验
类型不明确的输入是高危源头,不能只用isset()或empty()判断:
- 数字型(如ID、分页数):强制转整型或用
filter_var($id, FILTER_VALIDATE_INT),再传入SQL - 字符型(如用户名、搜索词):限制长度、字符集,例如
preg_match('/^[a-z0-9_\x{4e00}-\x{9fa5}]{2,20}$/u', $str)(含中文白名单) - 禁止对字符型参数仅做
addslashes()或mysql_real_escape_string()——这些已被证明可被宽字节等手法绕过
ORDER BY、LIMIT、表名、字段名必须白名单硬控
这些位置无法使用参数化,数据库不支持占位符,必须用固定列表做映射:
立即学习“PHP免费学习笔记(深入)”;
- 排序字段:
$allowed = ['id', 'title', 'created_at']; $sort = in_array($_GET['sort'] ?? '', $allowed) ? $_GET['sort'] : 'id'; - 分页数量:
$limit = min(max((int)($_GET['limit'] ?? 20), 10), 100); - 动态表名或字段名:先用
array_flip(['user' => 1, 'order' => 1])建立键值反查,再判断是否存在,比正则更安全
关闭错误回显并统一捕获异常
报错注入的危害在于暴露结构,生产环境必须隐藏所有数据库错误细节:
- 禁用
display_errors:ini_set('display_errors', '0');,同时确认error_reporting不含E_WARNING或E_NOTICE - 所有数据库操作包裹
try/catch,异常只记录日志,绝不输出$e->getMessage() - 若用MySQLi,避免在
mysqli_query()后直接调用mysqli_error()输出错误——这是报错注入的典型通道



















