Java安全 - FreeMarker模版注入浅析
字数 1110 2025-08-19 12:42:40
FreeMarker模板注入漏洞分析与防御
一、FreeMarker简介
FreeMarker是一款基于Java的模板引擎,主要用于MVC模式的Web开发中生成动态HTML页面。它通过将模板与数据模型结合来生成输出文本。
二、FreeMarker模板注入原理
FreeMarker模板注入(FreeMarker Template Injection, FTI)是一种服务器端模板注入(SSTI)漏洞,当攻击者能够控制模板内容或模板中的表达式时,可以执行任意代码。
注入点产生原因
- 直接使用用户输入作为模板内容
- 用户输入被拼接进模板表达式
- 不安全的配置导致内置危险方法可被调用
三、漏洞利用方式
基本注入语法
<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("whoami") }
常用危险类和方法
freemarker.template.utility.Execute- 执行系统命令freemarker.template.utility.ObjectConstructor- 构造任意对象freemarker.template.utility.JythonRuntime- 执行Python代码
实际利用示例
// 执行系统命令
<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("id") }
// 创建任意对象
<#assign ob="freemarker.template.utility.ObjectConstructor"?new()>
${ ob("java.lang.ProcessBuilder","calc").start() }
// 读取文件内容
<#assign f="freemarker.template.utility.ObjectConstructor"?new()>
${ f("java.io.File","/etc/passwd").getText() }
四、漏洞检测方法
- 基本检测:
${7*7}观察是否返回49 - 表达式检测:
<#assign a="freemarker.template.utility.ObjectConstructor"?new()>观察是否报错 - 完整检测:尝试执行无害命令如
whoami
五、防御措施
1. 输入验证与过滤
- 对用户输入进行严格过滤,特别是
<#、${等模板语法标记 - 使用白名单机制限制允许的字符
2. FreeMarker安全配置
// 禁用危险内置方法
Configuration cfg = new Configuration();
cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
// 或完全禁用所有内置方法
cfg.setNewBuiltinClassResolver(TemplateClassResolver.NOOP_RESOLVER);
3. 沙箱环境
- 使用FreeMarker的沙箱功能限制模板执行权限
- 配置模板加载器为安全模式
4. 其他措施
- 避免将用户输入直接作为模板内容
- 使用静态模板,动态内容仅作为数据传入
- 定期更新FreeMarker版本,修复已知漏洞
六、实际案例分析
案例1:用户输入直接作为模板
String templateContent = request.getParameter("template");
Template template = new Template("name", new StringReader(templateContent), cfg);
漏洞原因:用户可完全控制模板内容,可插入任意FreeMarker代码。
案例2:表达式注入
String username = request.getParameter("username");
String template = "Welcome ${" + username + "}!";
漏洞原因:用户输入被直接拼接进表达式,可闭合原有表达式插入恶意代码。
七、FreeMarker安全开发最佳实践
- 始终使用预定义的静态模板
- 将用户输入作为数据模型传递,而非模板内容
- 启用FreeMarker的安全配置
- 避免字符串拼接构建模板
- 定期审计模板使用代码
八、参考资源
- FreeMarker官方安全文档
- OWASP SSTI防御指南
- FreeMarker CVE漏洞列表
通过以上措施,可以显著降低FreeMarker模板注入的风险,确保应用安全。