加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.52jx.cn/)- 应用程序、AI行业应用、CDN、低代码、区块链!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP Web安全实战:SQL注入防护全解

发布时间:2026-09-25 10:30:45 所属栏目:PHP教程 来源:DaWei
导读:一个月之前,我接手了一个老项目的安全重构——那是个用PHP 5.6写的电商后台,管理员登录接口被曝出SQL注入漏洞,攻击者能直接绕过认证获取数据库权限。测试时我输入了`admin' -- `,结果系统直接返回了“登录成功”,连密码都

一个月之前,我接手了一个老项目的安全重构——那是个用PHP 5.6写的电商后台,管理员登录接口被曝出SQL注入漏洞,攻击者能直接绕过认证获取数据库权限。测试时我输入了`admin' -- `,结果系统直接返回了“登录成功”,连密码都没校验——这不就是教科书级的SQL注入吗?当时后端代码里全是这种拼接SQL的写法:`$sql = "SELECT FROM users WHERE username='".$username."' AND password='".$password."'";`,连最基本的`addslashes()`都没用,更别说预处理了。

文章配图,仅供参考

很多人觉得PHP的`mysql_`函数早被淘汰了,但实际项目中,尤其是老系统,这种危险写法依然存在——我查了下那个项目的代码库,发现70%的数据库操作还在用`mysql_query()`,而`mysqli_prepare()`和PDO预处理的使用率不到5%。更离谱的是,有个查询用户订单的接口,参数直接拼进了`LIMIT`子句里,攻击者输入`0,1; DROP TABLE orders--`就能删库,这哪是漏洞,简直是定时炸弹!

新技术在这时候就派上大用场了——我第一反应是换PDO预处理,但老项目用的是PHP 5.6,部分服务器还没升到7.0,PDO的兼容性没问题,但团队对它的熟悉度不够。于是我先在核心接口(比如登录、支付)里强制用`mysqli_prepare()`,比如把原来的拼接SQL改成:

`$stmt = $mysqli->prepare("SELECT FROM users WHERE username=? AND password=?");`
`$stmt->bind_param("ss", $username, $password);`
`$stmt->execute();`

这样参数和SQL分离,攻击者就算输入`admin' OR '1'='1`,也会被当成字符串处理,根本没法注入。测试时我故意在用户名里输`admin' -- `,系统直接报错“参数绑定失败”,而不是像之前那样登录成功——这效果,立竿见影!

但预处理不是万能的——有个案例让我印象深刻:之前有个团队用预处理处理搜索接口,参数是`$keyword`,结果攻击者输入`%'; DROP TABLE products--`,虽然预处理阻止了直接注入,但因为`LIKE`语句里用了`%`通配符,系统还是把`%'; DROP TABLE products--`当成了搜索关键词,导致SQL语法错误,数据库连接直接断开。后来他们发现,问题出在没对`$keyword`做长度限制和特殊字符过滤——预处理能防注入,但防不了恶意参数导致的逻辑错误,所以还得配合输入验证,比如用`filter_var($keyword, FILTER_SANITIZE_STRING)`去掉危险字符,再限制长度不超过50字。

还有个细节很多人忽略:存储过程也能被注入!我之前见过一个项目,用存储过程处理订单查询,参数直接拼进`EXEC`语句里,攻击者输入`1; DELETE FROM orders--`就能删数据。后来改用`sp_executesql`带参数绑定,才彻底堵住漏洞——这说明,防护不能只盯着代码层,数据库层面的安全也得考虑,比如给存储过程参数加类型检查,或者限制普通用户的执行权限。

新技术里,我最看好的是PHP 8.1的`FILTER_VALIDATE_BOOL`和`FILTER_VALIDATE_FLOAT`——以前验证布尔值或浮点数,得自己写正则,现在直接`filter_var($input, FILTER_VALIDATE_BOOL)`就能搞定,既安全又方便。比如有个接口接收`is_admin`参数,原来用`(bool)$input`转换,攻击者传`1 OR 1=1`,系统会当成`true`,导致权限提升;现在用`FILTER_VALIDATE_BOOL`,非法值直接返回`false`,攻击者没法绕过——这比自己写验证逻辑靠谱多了。

但说实话,光靠技术不够——我之前给一个团队做安全培训,讲完预处理和输入验证,他们觉得“懂了”,结果代码审计时发现,还是有人用`mysql_query()`拼接SQL,理由是“老代码改起来麻烦”或者“预处理性能差”。后来我直接在CI流程里加了SQL注入检测工具(比如SQLMap),每次提交代码自动跑扫描,发现漏洞就阻断合并——技术+流程,才真正管用。

下一步我打算研究下PHP的RASP(运行时应用自我保护)技术——比如用`Snuffleupagus`扩展,它能动态监控SQL查询,发现可疑操作直接拦截,连预处理都绕不过去。不过这玩意儿配置有点复杂,得先在测试环境跑通,再慢慢推到生产——安全这事儿,永远没有终点,对吧?

(编辑:站长网)

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