|
去年秋天,洞修一个做外贸站的复工朋友半夜给我发消息,说网站首页被挂了一串赌博链接。洞修我让他把源码打包发过来,复工翻了一遍,洞修问题出在一个两年前的复工图片上传接口——move_uploaded_file后面没接类型校验,攻击者传了个.php.jpg,洞修服务器直接当PHP执行了。复工这种漏洞在PHP项目里太常见了,洞修不是复工代码写得多烂,而是洞修写的时候根本没往那方面想。修的复工时候也简单,加个getimagesize()判断,洞修再改一下Nginx的复工解析规则,十分钟搞定。洞修但找这个漏洞花了我两个小时。 所以“PHP漏洞修复工具”这东西,核心价值不在修,在找。市面上工具不少,RIPS、SonarQube、Psalm、PHPStan,各有各的脾气。RIPS对污点分析做得细,能追踪$_GET到system()的完整路径,但商业版贵得离谱。开源方案里, Psalm的--taint-analysis模式其实够用,配置稍微麻烦点,得写个psalm.xml,把$_GET、$_POST、$_COOKIE标记为taint source,然后跑一遍就能列出所有可疑的sink点。我自己的习惯是CI里挂一个Psalm,每次push自动扫,扫出高危就阻断合并。 不过工具扫出来的东西,误报率不低。上周Psalm报了一个echo $_GET['id'],说XSS风险。我看了下上下文,那个id在前面已经被intval()转过了,Psalm没识别出来。这种时候就得手动加/** @psalm-suppress TaintedHtml */注解,或者干脆写个自定义的intval类型推断插件。工具是死的,人是活的,别指望一键修复。真正危险的漏洞——反序列化、文件包含、命令注入——往往藏在业务逻辑深处,静态扫描很难覆盖全。 修复环节,我一般分三步走。第一步是隔离,把有漏洞的入口先用WAF规则挡掉,比如ModSecurity加一条SecRule ARGS "@contains .." "deny",争取时间。第二步是改代码,能参数化查询就参数化,能白名单就白名单,别用addslashes这种糊弄事儿的函数。第三步是回归测试,把原来能触发的payload再打一遍,确认堵住了。有次我修一个unserialize漏洞,改完忘了测反序列化链,结果攻击者换了个__destruct魔术方法又绕过去了。教训就是:修完必须用原exp验证。 还有个坑是PHP版本本身。7.4之前的create_function、8.0移除的each(),这些废弃函数本身就是漏洞温床。我见过一个老项目还在用mysql_*系列,连mysql_real_escape_string都没用对,修起来不如直接重写。工具能帮你列出来,但换不换、怎么换,得看业务能不能停。我的建议是:新项目直接上PHP 8.2,老项目用Rector做自动化升级,配合PHPCompatibility扫一遍,能省不少事。 最后说个实在的:没有任何工具能替代代码审计的经验。工具跑一万次,不如人盯着eval、assert、preg_replace的/e修饰符看十分钟。我电脑里常备一个grep脚本,专门搜这些危险函数,配合git log看最近谁动过这些文件。漏洞修复工具是辅助,是安全带,不是自动驾驶。你得上路,得看路,得知道哪儿有坑。 |