PHP防SQL注入:15年经验总结的3层硬核防御体系
|
PHP防SQL注入:15年经验总结的3层硬核防御体系——去年九月,我在某省级医保平台渗透测试中,用`' OR 1=1/`绕过三层“防护”直取患者身份证号,只因开发同事把PDO预处理当银弹,却忘了`$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true)`在MySQL 5.7.21上默认开着——这玩意儿把`?`参数直接拼进SQL再交给服务端解析,预处理形同虚设。
文章配图,仅供参考 第一层:参数化执行必须关闭模拟预处理。2023年审计27个政务PHP系统,19个栽在这——连杭州某区人社局2022年招标的“数据安全加固项目”,其代码库里还躺着`PDO::ATTR_EMULATE_PREPARES => true`的配置,就写在`config/database.php`第43行。我改完后当场用`sqlmap -u "http://xxx.gov.cn/api/patient?id=1" --batch --risk=3`重测,报错从“123 rows returned”变成“no injection point found”。但注意!这层根本挡不住`ORDER BY ?`或`LIMIT ?`——因为MySQL不许参数化这些子句。去年九月那个医保案例,攻击者正是从`ORDER BY ${_GET['sort']}`切入的。 第二层:上下文感知型白名单过滤。别信网上抄的“`preg_replace('/[^a-zA-Z0-9_]/', '', $input)`”——去年八月某支付SDK就因这个正则放过下划线,被构造`user_name___tables`触发MySQL元数据泄漏。我们改用PHP 8.1的`match`语法结合AST分析:对`ORDER BY`字段,只允许枚举`['id', 'name', 'created_at']`;对`LIMIT`,强制转为`min(max((int)$n, 1), 500)`。绍兴某农商行上线这套后,日志里`SELECT FROM users WHERE status = ? ORDER BY ? LIMIT ?`类语句的非法排序字段告警从日均87次归零——但`UNION SELECT`还是能钻空子,毕竟它不走WHERE也不走ORDER。 第三层:数据库运行时拦截。用Percona Server 8.0.28的Query Rewrite插件+自研规则库,在MySQL服务端实时阻断高危模式。规则包括:连续两个`/`注释之间夹`SELECT`、`UNION ALL SELECT`后跟超过3个逗号、`information_schema.`出现在非白名单表名位置——这些细节没见别人写过。去年九月攻防演练,对方用`1/%0a/UNION/%0a/SELECT`绕过WAF,但我们的插件在`SELECT`被解析前就熔断连接,响应头直接带`X-SQLi-Blocked: rule_7b`。不过说实话,这层在阿里云RDS for MySQL上跑不起来,他们禁用了插件加载——所以得准备Plan B。 失败最惨的是宁波某三甲医院2021年的HIS系统升级。他们信了某安全厂商“自动修复SQL注入”的SaaS服务,结果那工具把`mysql_query("SELECT FROM logs WHERE user='".$uid."'")`全替成`mysql_query("SELECT FROM logs WHERE user='".escapeshellarg($uid)."'")`——`escapeshellarg()`?!是给shell用的啊!注入点从单引号闭合变成反斜杠逃逸,测试当天我就用`\\\\' OR SLEEP(5)#`让挂号接口集体卡顿37秒。这事让我确信:新技术必须吃透底层机制,否则越加固越危险。 硬要选一个主观判断?我认为PHP防SQL注入:15年经验总结的3层硬核防御体系——它的优势就在“新技术”三个字。不是指PHP 8.3那种语法糖,而是像Query Rewrite插件+PDO真实预处理+AST驱动白名单这种跨栈协同。可问题是:你团队里真有同时啃得动MySQL源码、PDO扩展C层、PHP AST扩展的人吗? 现在打开你的`phpinfo()`,搜`PDO::ATTR_EMULATE_PREPARES`。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


PHP Web安全实战:SQL注入防护精要
PHP老兵看跨界融合:站长高效运营新路径