序列化漏洞如何检测修复

wen 网络安全 28

检测方法与修复实战指南

目录导读

  1. 什么是序列化漏洞?核心危害与攻击原理
  2. 序列化漏洞检测:5大关键技术手段
  3. 序列化漏洞修复:从代码到架构的完整方案
  4. 常见问题解答(FAQ)

什么是序列化漏洞?核心危害与攻击原理

1 漏洞本质

序列化(Serialization)是将对象转换为可传输的字节流或字符串格式的过程;反序列化(Deserialization)则是逆向还原过程,当应用程序未经安全验证直接反序列化外部输入数据时,攻击者能够构造恶意序列化数据,触发服务器上的任意代码执行、远程命令执行或拒绝服务攻击。

序列化漏洞如何检测修复

2 攻击流程示意图

攻击者构造恶意Payload → 注入到HTTP请求参数/Cookie/Session → 
服务器调用readObject() → 触发构造函数和魔术方法 → 执行系统命令

以Java为例,攻击者利用ObjectInputStream.readObject()方法,通过修改序列化数据中的类的属性值,触发Runtime.getRuntime().exec()等危险方法。

3 典型危害场景

  • Java反序列化:Apache Commons Collections、Fastjson、Jackson等库的已知漏洞(如CVE-2015-7501)
  • PHP反序列化:利用unserialize()函数配合__wakeup()__destruct()魔术方法
  • Python反序列化pickle模块的代码执行风险
  • .NET反序列化:BinaryFormatter、NetDataContractSerializer等

问答1

Q: 为什么序列化漏洞被称为“无文件攻击”?
A: 因为攻击载荷完全存在于网络传输的数据流中,不依赖上传恶意文件,因此传统杀毒软件和文件监控难以检测。


序列化漏洞检测:5大关键技术手段

1 静态代码扫描(SAST)

  • 工具推荐:Fortify、Checkmarx、SonarQube(配合规则库)
  • 检测重点
    • 查找readObject()unserialize()pickle.loads()等函数调用
    • 识别未进行类型过滤的ObjectInputStream重写
  • 局限性:对动态反射调用链的误报率较高

2 动态行为分析(DAST)

  • 工具:Burp Suite Pro(配合反序列化插件)、Acunetix
  • 操作步骤
    1. 拦截HTTP请求,寻找序列化数据格式(如Java的aced0005十六进制头、PHP的a:1:{s:4:”test”}
    2. 使用ysoserial(Java)、PHPGGC(PHP)等工具生成测试Payload
    3. 观察响应耗时(差异化响应)或错误信息判断是否存在漏洞
  • 技巧:针对Fastjson,尝试发送@type字段探测

3 依赖库版本审计

  • 检测命令(以Maven为例):
    mvn dependency-check:check -DfailBuildOnCVSS=7
  • 关键库版本要求
    • Apache Commons Collections:升级至3.2.2+ 或使用4.1+
    • Jackson:2.10.0以上版本
    • Fastjson:1.2.83以上版本(并启用safeMode
    • .NET BinaryFormatter:已被标记为不安全,建议替换

4 安全测试框架自动化

  • OWASP ZAP:其反序列化扫描器可检测多种语言
  • Nikto:内置部分常见Payload测试
  • 自定义POC脚本:使用Python编写自动化检测工具,结合ysoserial动态生成Payload

5 流量异常监控

  • 检测特征
    • Base64编码中的rO0ABX(Java序列化标记)
    • 数据包含@type字段(Fastjson)
    • 参数包含O:8:(PHP对象标记)
  • 工具:WAF规则(ModSecurity)、ELK实时分析

问答2

Q: 生产环境中无法直接发送攻击Pay load怎么办?
A: 采用“白盒审计”策略:重点审查第三方依赖库版本是否在CVE列表内,并使用“黑盒+白盒”组合检测:先通过SAST锁定可疑函数,再用DAST对指定接口进行精准测试。


序列化漏洞修复:从代码到架构的完整方案

1 首选方案:禁止反序列化不可信数据

  • 代码示例(Java):

    // 错误做法
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(request.getParam("data")));
    // 修复后:仅接受JSON格式并做结构校验
    String jsonStr = request.getParam("data");
    MyObj obj = JSON.parseObject(jsonStr, MyObj.class, MyFilter.class);
  • 哲学:不信任任何外部序列化输入,转而使用安全的序列化格式(如JSON、Protocol Buffers)

2 强类型过滤与白名单机制

  • 实现方式

    // Java自定义ObjectInputStream
    class SafeObjectInputStream extends ObjectInputStream {
        private static final Set<String> ALLOWED_CLASSES = Set.of("com.example.User", "java.lang.String");
        @Override
        protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
            if (!ALLOWED_CLASSES.contains(desc.getName())) {
                throw new InvalidClassException("Unexpected class: " + desc.getName());
            }
            return super.resolveClass(desc);
        }
    }
  • 注意:白名单必须非常严格,仅包含业务必需的类

3 升级依赖库与启用安全配置

组件 最低安全版本 额外配置
Fastjson 2.83 ParserConfig.getGlobalInstance().setSafeMode(true);
Jackson 10.0 禁用default typing:mapper.enableDefaultTyping(DefaultTyping.NON_FINAL)
Pickle (Python) 不升级 完全避免使用;改用jsonmsgpack

4 纵深防御:WAF与运行时防护

  • Web应用防火墙:编写规则拦截序列化特征 (ModSecurity规则示例):
    SecRule REQUEST_BODY "@contains rO0ABX" "id:12345,phase:2,deny,status:403"
  • RASP(运行时应用自保护):如Contrast Security、Sqreen,可在运行时拦截反序列化操作

5 框架层面解决方案

  • Spring Boot:启用spring.autoconfigure.exclude排除风险组件
  • Fastjson:使用2.83版本并配置AutoType白名单
  • Java 17+:使用Record类型减少序列化风险(默认不可序列化)

问答3

Q: 使用了白名单后,业务需要新增类怎么办?
A: 实施“审批+自动化”流程:开发提交PR时,强制检查是否涉及反序列化类修改;管理员审核并在ALLOWED_CLASSES中添加,测试环境验证无误后上线。


常见问题解答(FAQ)

Q1: 为什么我的序列化数据经过了加密,还需要修复?
A: 端口嗅探不是唯一威胁,攻击者若获得加密密钥(如通过SSRF、日志泄露),密文仍可被解密并反序列化,加密仅保护传输机密性,不解决反序列化本身的逻辑漏洞。

Q2: 使用Gson代替Fastjson是否安全?
A: Gson默认不会调用对象的构造函数自动触发危险方法,但若使用了RuntimeTypeAdapterFactory或自定义反序列化器,仍然存在风险,建议:Gson默认比Fastjson更安全,但最佳实践仍是避免使用任何自动反序列化机制。

Q3: 如何修复遗留系统的序列化代码?
A: 采用“重写优于修补”策略:

  1. 识别所有反序列化入口(通常集中在Session、Cookie、RPC调用)
  2. 逐步替换为JSON格式,并添加严格的数据校验schema(如JSON Schema)
  3. 在替换完成前,启用WAF绕过特征拦截 + 白名单ObjectInputStream

Q4: PHP反序列化漏洞修复有什么特殊点?
A: 禁用unserialize()函数,使用json_decode()并配合类属性验证,若必须使用,设置allowed_classes参数:

$obj = unserialize($data, ['allowed_classes' => ['MySafeClass']]);

并将'allowed_classes'设置为false阻止所有对象反序列化。


核心行动清单

  1. 立即扫描所有第三方依赖库版本,更新至安全版本
  2. 审计所有readObjectunserializepickle.loads调用,添加白名单
  3. 部署WAF规则拦截序列化特征流量
  4. 针对遗留系统制定“分阶段替换”计划,优先替换Session存储

最终建议:将序列化漏洞纳入CI/CD门禁,使用maven dependency-checknpm audit等工具自动阻断风险引入,并定期进行红蓝对抗检验修复效果。

抱歉,评论功能暂时关闭!