字符串拼接SQL直接等于开门放攻击者,因PHP不自动转义$_POST、$_GET内容,数据库无法区分逻辑与数据,导致SQL注入;需用PDO预处理+bindParam隔离逻辑与数据,并注意字符集统一、白名单校验及边缘路径防护。

字符串拼接SQL为什么直接等于开门放攻击者
因为PHP不做任何自动转义,$_POST、$_GET 里的内容原样塞进SQL语句,数据库引擎就照单全收——它分不清哪段是逻辑、哪段是数据。
比如这行代码:$sql = "SELECT * FROM users WHERE username = '$username'";,只要用户提交 admin' OR '1'='1,最终执行的就是:SELECT * FROM users WHERE username = 'admin' OR '1'='1'。条件恒真,整张表被拖走。
- 单引号
'被用来闭合字符串,攻击者用它“跳出”原有字段边界 - 分号
;在多数驱动中允许拼接多条语句(如admin'; DROP TABLE users; --) -
--或/* ... */可注释掉后续校验逻辑,绕过密码、状态等判断 - 宽字节编码(如
%df%27)在gbk环境下可能绕过mysql_real_escape_string,让转义失效
mysqli_real_escape_string 不能当救命稻草
它只是对特殊字符加反斜杠,前提是:连接字符集必须和页面/输入一致,且全程使用同一编码。一旦 SET NAMES gbk 和 utf8mb4 混用,mysqli_real_escape_string 就会漏逃——这是2025年多个线上漏洞的共性原因。
- 它不处理数字型参数(比如
id=123 OR 1=1),需手动(int)强转 - 它无法防护
ORDER BY、LIMIT、UNION SELECT这类结构化位置的注入 - 它不校验长度、类型、业务规则(比如手机号不该含字母),属于纯语法层补丁
PDO prepare + bindParam 才是真正隔离逻辑与数据
预处理语句让数据库先编译 SQL 模板(不含任何用户值),再把参数作为独立数据包传入。哪怕你传 admin'; DROP TABLE users; --,数据库也只把它当一个普通字符串值,不会解析成指令。
立即学习“PHP免费学习笔记(深入)”;
- 连接时必须显式声明字符集:
charset=utf8mb4,否则 PDO 可能降级为latin1导致宽字节风险 - 占位符只能用于值(
WHERE、INSERT字段值等),不能用于表名、列名、排序字段——这些必须靠白名单校验 -
LIKE查询要手动加通配符:$search = '%' . $_POST['q'] . '%'; $stmt->execute([$search]);,不能写成WHERE name LIKE '%?%' - 绑定类型建议明确指定:
bindParam(':id', $id, PDO::PARAM_INT),避免字符串隐式转换引发意外行为
最容易被忽略的三个“安全假象”
很多开发者以为加了过滤就万事大吉,但真实攻防中,破防点往往藏在边缘路径里:
- JSON 接口没做 Content-Type 校验,攻击者发
application/x-www-form-urlencoded包裹恶意参数,绕过 JSON 解析层的过滤 - 日志记录或调试输出里拼接了原始 SQL,导致错误信息泄露表结构、字段名,为后续 UNION 注入铺路
- 后台管理接口用了预处理,但导出 Excel 的
WHERE条件却是字符串拼接——攻击面不在主流程,而在辅助功能



















