如何在Thymeleaf中禁用静态上下文及方法调用,保障自定义模板安全?
Absolutely, you can lock down Thymeleaf to exactly the safe subset of features you need—blocking arbitrary Java method calls, static member access, and only allowing basic conditionals, loops, and object field access. Here's how to implement this effectively:
1. Control Expression Evaluation (Core of the Restriction)
Thymeleaf uses either SpringEL (in Spring environments) or OGNL (standalone) for evaluating expressions. The key is to customize the evaluation context to filter out unsafe operations.
For Spring-Based Applications (SpringEL)
Override the evaluation context in your SpringTemplateEngine configuration to block unwanted method calls and static access:
@Bean public SpringTemplateEngine safeTemplateEngine() { SpringTemplateEngine engine = new SpringTemplateEngine(); engine.setTemplateResolver(yourTemplateResolver()); // Customize the SpringStandardDialect to enforce security rules engine.addDialect(new SpringStandardDialect() { @Override public IEvaluationContext createEvaluationContext( IExpressionContext expressionContext, IProcessingContext processingContext) { StandardEvaluationContext context = (StandardEvaluationContext) super.createEvaluationContext(expressionContext, processingContext); // Block all method calls except getter/is methods (for field access) context.setMethodFilter((method, target) -> { String methodName = method.getName(); // Allow standard getter methods (getXxx()) and boolean isXxx() methods return (methodName.startsWith("get") && method.getParameterCount() == 0) || (methodName.startsWith("is") && method.getParameterCount() == 0); }); // Block ALL static method access context.setStaticMethodFilter(method -> false); // Block static field access context.addPropertyAccessor(new BeanWrapperPropertyAccessor() { @Override public boolean canRead(EvaluationContext ctx, Object target, String name) throws AccessException { // Prevent accessing static fields like T(java.lang.System).out if (target instanceof Class) { return false; } return super.canRead(ctx, target, name); } }); return context; } }); return engine; }
For Standalone Thymeleaf (OGNL)
If you're not using Spring, configure OGNL's security manager to restrict access:
TemplateEngine safeTemplateEngine = new TemplateEngine(); safeTemplateEngine.setTemplateResolver(yourTemplateResolver()); // Custom OGNL parser with security rules OGNLExpressionParser expressionParser = new OGNLExpressionParser(); expressionParser.setOgnlContextFactory((ctx, processingCtx) -> { OgnlContext ognlContext = (OgnlContext) Ognl.createDefaultContext(ctx); ognlContext.setSecurityManager(new OgnlSecurityManager() { // Allow only getter/is methods for instance objects @Override public boolean isMethodAccessAllowed(Object target, Method method, Object[] args) { String methodName = method.getName(); return (methodName.startsWith("get") && method.getParameterCount() == 0) || (methodName.startsWith("is") && method.getParameterCount() == 0); } // Block all static method calls @Override public boolean isStaticMethodAccessAllowed(Class<?> clazz, Method method, Object[] args) { return false; } // Allow instance field access (optional, for direct field access instead of getters) @Override public boolean isFieldAccessAllowed(Object target, Field field) { return true; } // Block all static field access @Override public boolean isStaticFieldAccessAllowed(Class<?> clazz, Field field) { return false; } }); return ognlContext; }); safeTemplateEngine.setExpressionParser(expressionParser);
2. Enforce Template Syntax Constraints
Even with expression restrictions, add an extra safety layer by validating user templates during upload/save:
- Allow only core attributes:
th:if,th:each,th:text,th:switch,th:case,th:with(basic flow control and data rendering) - Reject any attributes that could execute arbitrary logic (though the expression rules already mitigate this, validation adds redundancy)
You can use Thymeleaf's TemplateParser to parse templates programmatically and flag forbidden attributes.
3. Test Edge Cases
Validate your setup with these critical scenarios:
- Arbitrary method calls:
${user.someCustomMethod("unsafe")}should throw an exception or be blocked - Static access:
${T(java.lang.Math).random()}or${T(java.lang.System).out}should be rejected - Valid field access:
${user.name}(viagetName()) or${user.isActive()}should work as expected
内容的提问来源于stack exchange,提问作者Daniël V




