|
去年帮一个朋友看他们公司刚上线的代码审计电商后台,登录逻辑里藏着这么一行:if ($_POST['password'] == $row['password'])。代码审计密码明文比对,代码审计数据库里存的代码审计也是明文。我问他为什么不用哈希,代码审计他说"项目赶,代码审计先跑起来再说"。代码审计三个月后,代码审计他们的代码审计用户数据在某个论坛上被公开叫卖。 代码审计不是代码审计拿着扫描器跑一遍就完事。工具能查出已知的代码审计CVE,但真正的代码审计漏洞往往藏在业务逻辑里,藏在开发者"觉得没问题"的代码审计地方。SQL注入、代码审计XSS这些老生常谈的代码审计东西,现在框架基本帮你挡住了。可框架管不了你写的业务代码。 我见过一个权限校验的写法:前端把用户ID放在cookie里,后端直接读cookie判断身份。改个cookie值就能以管理员身份登录。这种问题扫描器报不出来,因为从语法上它完全合法。你得理解这段代码在干什么,数据从哪来,到哪去,中间有没有人能动它。 审计的时候我习惯先找"入口"。所有接收外部输入的地方——HTTP请求参数、文件上传、API回调、甚至数据库里读出来的数据——都是潜在的污染源。然后顺着数据流往下追,看它最终有没有落到危险函数里。这个过程叫污点分析,手工做很累,但比工具靠谱。 有个案例印象很深。一个CMS的文件删除功能,路径参数过滤了../,但没过滤....//。攻击者构造....//....//etc/passwd,过滤函数把中间的../删掉之后,剩下的又拼成了../../etc/passwd。这种绕过思路,规则引擎很难覆盖全。 PHP项目里有个高频问题:in_array()没加第三个参数true。松散比较下,in_array(0, ['a', 'b'])返回true。如果这个函数的返回值用来做权限判断,0就能绕过所有字符串白名单。这类坑在文档里有写,但没踩过的人不会注意。 Java那边,反序列化漏洞前几年炸了一波。根本原因是ObjectInputStream.readObject()会执行readObject方法里的代码,攻击者能构造恶意字节流触发任意命令执行。很多开发者到现在都没搞明白,为什么一个"读对象"的操作能变成RCE。 审计报告写完不是终点。我见过太多修复方案是"加个WAF规则拦一下"。WAF能挡已知payload,改个编码就绕过去了。真正的修复得改代码——参数化查询、输出编码、最小权限、输入白名单。这些做起来麻烦,但管用。 说个反直觉的事:代码审计里最危险的往往不是那些复杂的加密实现或者多线程逻辑,而是看起来最简单的字符串拼接。SQL语句拼接、命令拼接、路径拼接——开发者觉得"我过滤了特殊字符",但过滤列表永远不全。不如换个思路:别拼,用参数化。 最后提一句,审计别人的代码之前,先审自己的。我每隔几个月会回头翻自己以前写的项目,每次都能找到新问题。不是技术退步了,是看问题的角度变了。代码审计本质上是跟自己的思维盲区较劲,工具只是辅助。 |