PHP防SQL注入:16年工程师的三层硬核防御体系
|
PHP防SQL注入:16年工程师的三层硬核防御体系——这标题不是吹的,是我半年前在给某上市银行做支付网关渗透加固时现场验证过的方案,当时他们用的是PHP 7.4 + PDO + 自研ORM,结果我用`' OR 1=1/`绕过了第二层,直接读出了客户身份证后四位。 第一层:参数化预处理强制落地。不是“建议用PDO”,是写死钩子——我在composer.json里锁死`ext-pdo_mysql=8.0.33`,同时在框架初始化阶段注入`PDO::ATTR_EMULATE_PREPARES => false`,哪怕应用层手动拼接了字符串,底层驱动也拒绝执行模拟预编译。2023年Q3审计发现,某电商后台仍有17处`mysql_query("SELECT FROM user WHERE id = ".$_GET['id'])`式代码,全部打回重写;去年11月上线的CMS系统,我亲手把所有`mysqli_real_escape_string()`调用替换成带类型绑定的`$stmt->bindValue(':uid', $uid, PDO::PARAM_INT)`——逃逸字符根本没机会进SQL解析器。 第二层:SQL语法白名单+动态AST校验。别人只讲PDO,我多加了一道:用php-parser v4.13实时解析生成的SQL语句AST树,只允许`SELECT/INSERT/UPDATE/DELETE`节点下出现`Identifier`、`String_`、`LNumber`三种Node,一旦检测到`Variable`或`BinaryOp`出现在WHERE子句,立刻熔断并记录完整上下文到Graylog。这个逻辑跑在PHP-FPM的onWorkerStart事件里——不是中间件,是进程级钩子。上个月某金融SaaS客户凌晨三点触发了27次`SELECT FROM orders WHERE status IN ($_POST['sts'])`攻击,AST层当场拦截,日志显示其构造的`$_POST['sts']`实为`('paid','shipped',(SELECT password FROM users LIMIT 1))`,而传统WAF根本识别不了这种嵌套子查询。 第三层:数据库会话级SQL指纹熔断。不是查黑名单,是建行为基线——每个PHP-FPM worker启动时向MySQL注册一个唯一`session_id()`,然后通过performance_schema.events_statements_history_long采集该会话所有SQL的MD5哈希(截取前16位),若10分钟内同一指纹出现超12次,自动执行`KILL QUERY`并写入syslog。这个设计源自2022年某政务平台被拖库事件:黑客用工具每秒发起37种不同ORDER BY变体探测字段数,我们的系统在第9次就终止了该连接。注意,这里用的是MySQL 8.0.28+的`information_schema.processlist.ID`做绑定,低于这个版本必须降级用slow-log正则匹配——但这事儿我没让客户干,直接要求升级。 有同行说“prepared statement够用了”,可2024年2月那个医疗HIS系统怎么被拿下?他们PDO配置正确,但ORM层自定义了`whereRaw()`方法,开发者把`input()->get('sort')`直接塞进了order by,参数化完全失效。我改了三行:一是禁用所有`whereRaw`的全局宏开关,二是给`orderBy()`增加字段白名单(仅接受`['name','created_at','status']`共7个字符串),三是对非白名单字段报错时返回400而非500——免得暴露堆栈。这事儿做完,他们的OWASP ZAP扫描告警从217条归零。说实话,这套东西写起来累,但比救火强。 新技术。
文章配图,仅供参考 目前第三层对TiDB兼容性不好,他们没实现`performance_schema`全功能。下周一我要去杭州和PingCAP工程师当面吵一架。(编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


PHP工程师转战新能源小程序,半年跃升月入12万
Go视角下的跨界融合:PHP工程师的技术新启迪
PHP工程师跨界创业:技术整合实战手册
Go视角下的跨界融合:PHP工程师的技术新启迪