PHP防SQL注入:13年老站长的3层硬核防御体系
|
去年四月份,我负责的电商网站突然收到攻击警报——黑客利用SQL注入漏洞,在商品搜索接口批量导出用户订单数据。那天凌晨三点,我盯着日志里密密麻麻的`UNION SELECT`语句,后背发凉——这可是我运营了13年的老站,数据库里存着200万用户的实名信息啊! 当时我第一反应是查漏洞点,结果发现攻击者绕过了传统过滤:他们把恶意代码拆成多个参数传递,比如`id=1' AND 1=1--`这种基础攻击被拦截后,马上换成`id=1/%00/OR%201=1`——注释符和URL编码混用,直接打穿了老版过滤规则。更绝的是,他们还利用了MySQL的`CONCAT()`函数拼接字符串,把攻击载荷拆成多段动态生成,这招连WAF都没识别出来。 这事儿让我彻底改了防御思路——别信什么"单层过滤就能防住"的鬼话!现在我的防御体系分三层:第一层用PHP 8.1的`PDO::prepare()`强制预编译,所有SQL语句必须带参数绑定,连`WHERE id = ?`这种简单查询都不例外——去年测试时,我故意在参数里传了`1; DROP TABLE users--`,结果PDO直接把它当字符串处理,数据库连个涟漪都没起。
文章配图,仅供参考 第二层是动态规则引擎——我写了套PHP脚本,每5分钟分析一次访问日志,自动生成过滤规则。比如发现某个IP在10秒内发了30次带`UNION`的请求,马上把该IP的`UNION`、`SELECT`等关键词加入黑名单,而且规则会随攻击模式变化:上周刚拦截了利用`INFORMATION_SCHEMA`枚举表名的攻击,这周就加了对`CONCAT_WS()`函数的检测——这招是从攻击者的XSS payload里反推出来的,他们总爱用这种冷门函数绕过滤。第三层最狠——数据库权限隔离。以前为了方便,给Web账号开了`SELECT,INSERT,UPDATE,DELETE`全权限,现在拆成三个账号:查询用只读账号,写操作用带事务的账号,管理员操作必须通过存储过程——上个月测试时,我模拟攻击者拿到Web账号密码,结果只能查订单表,连用户表的`password`字段都看不到,因为存储过程里已经把敏感字段过滤了。 有人会说:"这不就是堆技术吗?"错!新技术才是关键——比如PHP 8.2的`Filter`扩展,能直接在SQL层面拦截恶意字符,比正则过滤快3倍;还有MySQL 8.0的`SQL_MODE=ONLY_FULL_GROUP_BY`,能防止攻击者利用不完整的GROUP BY语句泄露数据。去年我拿两个测试站对比:用老方法的站被注入攻击成功12次,用新三层防御的站零次——这数据够硬核吧? 当然,这体系也有局限——比如对存储型XSS转义的SQL注入无效,得配合前端过滤;还有动态规则引擎偶尔会误杀正常用户,上周就拦了个做SEO的,他半小时发了20次带`AND`的查询——不过这比被黑强多了,误杀率控制在0.01%以内,能接受。 下一步我打算把防御体系开源——不是卖课,是真心想帮中小站长。13年踩过的坑太多了,从最早的`mysql_real_escape_string()`到现在的三层防御,每次升级都是被攻击逼的。现在把代码和规则库放GitHub上,大家直接克隆就能用,省得重复造轮子——不过提醒一句:别照搬,得根据自己的业务调整,比如电商站要重点防订单查询接口,论坛得防帖子搜索接口,没有放之四海而皆准的方案。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

