加入收藏 | 设为首页 | 会员中心 | 我要投稿 航空爱好网 (https://www.52kongjun.com/)- 自然语言处理、云硬盘、数据治理、数据工坊、存储容灾!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP Web安全实战:15年经验详解SQL注入防护

发布时间:2026-09-24 13:29:18 所属栏目:PHP教程 来源:DaWei
导读:去年4月,我接手过一个电商平台的渗透测试项目——客户反馈订单查询接口存在异常数据泄露,测试后发现是典型的布尔盲注漏洞。攻击者通过构造`id=1 AND (SELECT 1 FROM users WHERE username='admin')=1`这类语句,能逐步枚

去年4月,我接手过一个电商平台的渗透测试项目——客户反馈订单查询接口存在异常数据泄露,测试后发现是典型的布尔盲注漏洞。攻击者通过构造`id=1 AND (SELECT 1 FROM users WHERE username='admin')=1`这类语句,能逐步枚举出整个用户表。这让我意识到,哪怕2023年的今天,SQL注入仍是PHP Web应用最顽固的漏洞类型之一——根据OWASP 2023报告,它仍占据Web攻击手段的前三名。

15年里,我见过最离谱的案例是某金融系统用字符串拼接直接拼SQL——开发人员觉得"反正内网访问安全",结果攻击者通过抓包修改`account_id=123`为`account_id=123; DROP TABLE transactions;`,直接清空了交易表。更讽刺的是,这个系统用的是PHP 5.6,连`mysqli_real_escape_string()`都没用,纯粹靠前端JavaScript校验输入——这种"防御"在抓包工具面前就像纸糊的。

文章配图,仅供参考

现在说新技术——我强烈推荐PDO预处理+参数绑定。去年修复那个电商平台漏洞时,我把所有动态查询改成了`$stmt = $pdo->prepare("SELECT FROM orders WHERE id = :id"); $stmt->bindParam(':id', $id, PDO::PARAM_INT);`。测试时故意传`id=1' OR '1'='1`,结果查询直接返回空——参数绑定会把输入当数据处理,而不是代码,彻底切断了注入路径。这比老式的`mysql_escape_string()`靠谱太多,后者连多字节编码的攻击都防不住。

但新技术也有坑——某次我帮朋友审计代码,发现他用PDO却没禁用模拟预处理(`PDO::ATTR_EMULATE_PREPARES => false`)。攻击者传`id=1; UPDATE users SET password='hacked'`,PDO居然把整个语句当参数传给了MySQL,导致注入成功。这事儿让我明白:新技术用不对,比不用更危险。现在我审核代码必查两点:是否禁用模拟预处理,是否所有动态参数都用了命名绑定(`:id`比`?`更易维护)。

还有个细节没人提——输入验证必须和预处理配合用。比如用户ID应该是数字,那除了用预处理,还得加`ctype_digit($id)`校验。去年有个案例,攻击者传`id=1e0`(科学计数法表示1),预处理能防注入,但业务逻辑可能把1e0当字符串处理,导致查询异常。所以我的原则是:预处理防注入,输入验证保业务逻辑——两者缺一不可。

承认个局限:完全防住所有注入不可能。比如存储过程调用、动态表名这些场景,预处理可能不够用。这时候我建议用白名单校验——比如表名只能是`orders`、`users`、`products`中的一个,其他直接拒绝。去年我帮某政府系统加固,他们用动态表名查不同部门数据,我让他们把表名存在配置文件里,通过部门ID映射表名,彻底杜绝了攻击者传`table=users; DROP TABLE`的可能。

下一步该干啥?如果你还在用`mysql_`函数,赶紧换PDO或mysqli——PHP 7.4已经移除了`mysql_`,继续用等于埋雷。如果已经用了预处理,检查是否禁用了模拟预处理、是否所有参数都绑定了、是否配合了输入验证。⭐️⭐️⭐️⭐️定期用sqlmap扫自己的应用——去年我扫出过3个隐藏的注入点,其中1个在分页参数里,开发人员根本没想到。

(编辑:航空爱好网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!