XMLDecoder不能读取不信任的XML数据,因为它会直接执行XML中声明的任意Java类构造、方法调用和字段赋值,等同于执行不受控的Java代码,极易被利用执行恶意操作。
XMLDecoder 为什么不能读不信任的 XML 数据
因为
会直接执行 XML 中声明的任意 Java 类构造、方法调用和字段赋值,等同于在 JVM 里跑了一段不受控的 Java 代码。只要攻击者能控制输入 XML,就能调用
、写文件、加载恶意类——漏洞利用门槛极低,且无需任何依赖。
常见错误现象:
看似是类找不到,实际可能是攻击者故意触发类加载失败来探测环境;更危险的是静默执行成功,连日志都不留。
使用场景:旧系统中用
做配置反序列化、UI 组件状态恢复、测试数据加载
参数差异:它不校验类名白名单,也不限制方法调用,
和私有字段赋值默认全开
兼容性影响:JDK 8u121+ 默认禁用部分高危类(如
),但绕过方式公开且简单,不能依赖这个“防护”
替代方案:用 JAXB 或 Jackson XML 替掉 XMLDecoder
JAXB(
)和 Jackson XML(
)都只做字段映射,不执行逻辑,前提是不用
引入自定义反序列化器。
实操建议:
立即学习
“
Java免费学习笔记(深入)
”;
优先选
:Jackson 对类型安全控制更细,可设
关闭自动类型识别
禁用 JAXB 的
和
外部实体加载(防 XXE)
所有目标类必须有无参构造函数 + public setter,否则解析失败而非执行任意代码
示例:用
读取配置时,明确指定类型
,不传
如果必须保留 XMLDecoder,至少加三道隔离
这不是推荐做法,而是给无法立即下线的老系统兜底。核心思路是切断它接触真实类路径、系统资源和反射能力的通路。
用自定义
加载
实例,只允许加载白名单里的几个基础类(如
、
)
在
策略中禁止
和
,JDK 17+ 需改用
后自行拦截(因 SecurityManager 已废弃但未移除)
预处理 XML:用正则或 SAX 解析器先扫描是否含
、
、
,命中即拒收——注意别漏掉换行/空格绕过(如
)
最容易被忽略的点:XMLDecoder 常藏在第三方库底层
很多老 UI 框架(如 Apache Pivot)、报表工具(JasperReports 早期版本)或序列化工具封装了
,你没直接写它,但它在运行时被调用。查法很简单:
启动时加
,搜
类加载记录
用
抓到正在运行的线程栈,看是否有
调用链
检查
里有没有
相关描述
修复时别只改自己写的代码,得确认依赖树里所有 jar 是否已升级到修复版本——比如 JasperReports 6.0.0+ 才彻底弃用
。
XMLDecoderRuntime.getRuntime().exec()java.lang.ClassNotFoundExceptionXMLDecodersetAccessible(true)ProcessBuilderjavax.xml.bind.JAXBContextXmlMapper@XmlJavaTypeAdapterXmlMapperDefaultTyping.NON_FINALsetEventHandlersetSchemaXmlMappermapper.readValue(xmlBytes, Config.class)Object.classClassLoaderXMLDecoderjava.lang.Stringjava.util.ArrayListSecurityManagerRuntimePermission("createClassLoader")FilePermissionSystem.setSecurityManager(null)method= XMLDecoder-verbose:classXMLDecoderjstackXMLDecoder.readObjectMETA-INF/MANIFEST.MFImplementation-Title: JavaBeansXMLDecoder