系统漏洞怎么修复
去年冬天,系统修复我帮一个做电商的漏洞朋友处理过一台服务器。网站后台突然多出十几个不存在的系统修复订单,金额全是漏洞零,收货地址栏填着乱码。系统修复他以为是漏洞数据库崩了,重启了三遍,系统修复没用。漏洞我上去看了一眼日志,系统修复发现有个陌生IP每隔几秒就往结算接口发一次请求,漏洞参数里夹着一段十六进制的系统修复字符串——典型的SQL注入尝试。漏洞不在代码逻辑,漏洞而在一个第三方支付插件里,系统修复那插件两年没更新过。漏洞
系统漏洞这东西,系统修复说白了就是程序在某个地方没按你预想的方式运行。可能是输入没过滤,可能是权限没校验,也可能是内存越界。修复的第一步,永远是先确认它真的存在。别急着打补丁,先复现。拿刚才那个例子,我在测试环境里手动构造了同样的请求,数据库果然返回了所有用户表的字段名。能复现,才算抓到实锤。
接下来是定位。很多人一上来就翻源码,几千个文件看到眼花。我的习惯是从流量入手。用Wireshark或者tcpdump抓包,找到异常请求的完整路径和参数。那个电商案例里,请求最终落在 /plugins/pay/notify.php 第47行。打开一看,$order_id = $_GET['id']; 后面直接拼进了SQL查询,连 intval() 都没加。这就是漏洞的根。
修复方式分几种。最直接的是改代码。把上面那行改成 $order_id = intval($_GET['id']);,或者用参数化查询。但改代码有风险——万一这个插件被其他地方调用,改了可能影响别的功能。所以我一般先在本地改,跑一遍回归测试。没问题再上预发布环境,观察一天日志。没异常才推生产。
有些漏洞改不了代码怎么办?比如第三方组件,你拿不到源码,或者厂商已经不维护了。那就得靠外围防护。WAF(Web应用防火墙)可以拦掉大部分已知攻击模式。但WAF不是万能的,它靠规则匹配,遇到变形过的payload照样漏。我见过有人用 /*!50000union*/ 这种注释绕过WAF的SQL注入规则。所以WAF只能当辅助,不能当解药。
还有一类漏洞是配置问题。比如Redis没设密码,直接暴露在公网。这种不需要改一行代码,改配置文件就行。但很多人不知道,或者知道了懒得改。我扫过一批IP,发现将近三成的Redis端口是敞开的,里面存着session或者缓存数据。攻击者连进去,写个SSH公钥,服务器就归他了。修复方法简单到可笑:bind 127.0.0.1 加上 requirepass。可就是没人做。
补丁管理也是个坑。很多公司有漏洞扫描器,扫出一堆CVE编号,然后呢?排个优先级,先修高危的。但高危的定义要看业务场景。一个只在内网运行的旧版Jenkins,和一台暴露在公网的Tomcat,同样是一个反序列化漏洞,风险等级完全不同。我的做法是:先看资产是否可达,再看数据是否敏感,最后才看CVSS评分。别被扫描器的红字牵着走。
修复完之后,必须验证。不是重启服务就算完。用原来的攻击载荷再打一次,看是否被拦截或报错。然后翻日志,确认没有新的异常请求。那个电商案例里,我改完代码后,用sqlmap跑了一遍,确认注入点没了。又观察了三天访问日志,那个陌生IP再也没出现过。
最后说个容易被忽略的点:修复漏洞不是终点,搞清楚它怎么进来的才是。是开发图省事直接拼接字符串?还是运维把测试环境暴露到了公网?还是第三方组件没人跟进更新?找到根因,才能避免下一个漏洞。我见过一个团队,同一个SQL注入漏洞,三个月内修了四次,每次都是不同文件。后来发现他们的代码规范里压根没提参数化查询。改了规范,问题才断根。
漏洞修复没有一劳永逸。今天修好了,明天可能又冒出一个。保持警惕,保持更新,保持怀疑。就这些。