jdk17及以上版本限制反射以抵御跨模块注入

最近看了3篇精彩的关于jdk17及以上版本可绕过模块化的文章:

1)JDK 17 TemplatesImpl ByPass 原理分析

2)JDK17不出网?Shiro反序列化极限RCE!

3)ClassPathXmlApplicationContext不出网利用

其中防守shiro反序列化可以用传统思路,直接jep290在java运行时增加VM启动参数:

//启动参数1
-Djdk.serialFilter=!com.sun.org.apache.xalan.internal.xsltc.**;!org.apache.commons.beanutils.**;

那如何在上述的 基础上 再进一步增加安全策略呢?

第一步:增加对TemplatesImpl的注入的防护策略

首先在应用main函数文件上引入相关包

//代码片段1
import jdk.internal.reflect.Reflection;
import javax.xml.transform.Templates;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

之后增加对TemplatesImpl和Templates的反射限制

//代码片段2
Reflection.registerMethodsToFilter(TemplatesImpl.class,Set.of("readObject","getOutputProperties","newTransformer"));
//javax.xml.transform.Templates 只有2个方法,都需要防护
Reflection.registerMethodsToFilter(Templates.class, Set.of("*"));

增加完之后启动,发现系统提示:

Exception in thread "main" java.lang.IllegalAccessError: 
class SerializeJDK8 (in unnamed module @0x6d311334) cannot access class 
jdk.internal.reflect.Reflection (in module java.base) 
because module java.base does not export jdk.internal.reflect to unnamed module @0x6d311334
at SerializeJDK8.main(SerializeJDK8.java:20)

对应在java执行启动时增加vm参数:

//启动参数2
--add-exports=java.base/jdk.internal.reflect=ALL-UNNAMED
--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED

代码解释:

#使用--add-exports导出包,意味着所有的public类型和成员都可以在编译和运行时访问。
#使用--add-opens  打开包,意味着其中的所有类型和成员(不仅是公共的!)随时可以访问。 

#对代码片段2进行说明:
#1、对TemplatesImpl进行导出才能限制它的反射,因为默认java17模块之间是封闭的
#2、getOutputProperties调用了newTransformer,所以应同时防护这两个函数
#3、TemplatesImpl类实现了Templates接口类,所以这两个类都要防护

第二步:增加对spel的注入的防护策略

//代码片段3
import org.springframework.cglib.core.ReflectUtils;
//针对恶意表达式:T(org.springframework.cglib.core.ReflectUtils).defineClass(...等
Reflection.registerMethodsToFilter(ReflectUtils.class,"defineClass");

第三步:以下是补强代码

在启动参数(1、2)和代码片段(1、2、3)的基础上增加几行:

//代码片段4

//1、之前导出了Reflection,所以还要保护其方法禁止随意反射
Reflection.registerMethodsToFilter(Reflection.class, Set.of("*"));

//2、防止反射sun.misc.Unsafe堵住bypass模块化限制的技巧,主要防御内存马
Reflection.registerMethodsToFilter(Unsafe.class, Set.of("theUnsafe"));
//如果使用java25可以不用上面这一行代码
//增加VM启动参数 --sun-misc-unsafe-memory-access=deny 禁止一切unsafe内存操作

//3、阻止反射Spring的单String构造函数发起的XXE、SPEL、bean等恶意利用
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
//这两个类没有继承Serializable,只需限制反射即可
Reflection.registerMethodsToFilter(ClassPathXmlApplicationContext.class,"ClassPathXmlApplicationContext");
Reflection.registerMethodsToFilter(FileSystemXmlApplicationContext.class,"FileSystemXmlApplicationContext");

以上代码目的是增加对常见的方法进行反射的限制,以减少未知攻击的可能性

 

总结:

1)反序列化时应对输入的流进行安全校验做到对未知漏洞的防护

2)限制跨模块操作和限制危险方法的反射,可以降低已知手段的风险

3)参照:https://alibaba.github.io/fastjson2/autotype_cn.html  对输入的校验使用白名单是目前已知最好的编码方式

 

posted @ 2025-10-01 13:32  国产大熊猫~  阅读(146)  评论(0)    收藏  举报