jdk17及以上版本限制反射以抵御跨模块注入
最近看了3篇精彩的关于jdk17及以上版本可绕过模块化的文章:
1)JDK 17 TemplatesImpl ByPass 原理分析
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 对输入的校验使用白名单是目前已知最好的编码方式

浙公网安备 33010602011771号