百万美元可以安全地与用户提供的模板一起使用吗?

时间:2017-07-01 09:40:38

标签: thymeleaf

在SaaS应用程序中,我有一些模板用于生成通知电子邮件或某些HTML页面。到目前为止,我还没有使用百日咳,到目前为止所有模板都是硬编码的,但我很乐意改变它,以便应用程序的用户可以自己编辑这些模板。问题是如果我允许用​​户自己编辑模板,用户可能会调用任何Java方法,这将完全损害系统安全性。

百万美元可以“沙盒化”还是可以禁用用户编辑模板环境中所有危险的功能? (为了执行,模板只接收带有getter和setter或java.util.Map的POJO,因此调用模型上的方法不是问题)

我尝试了什么

最明显的问题是OGNL / SpringEL。这些表达的力量可能很大,但它们也非常危险。我只需要从模型中调用getter。所以我试着像这样实现我自己的表达式解析器(以下只是快速和肮脏的东西作为概念证明,它不是“完成”):

final TemplateEngine templateEngine = new TemplateEngine();
final StandardDialect dialect = new StandardDialect();
dialect.setExpressionParser(new IStandardExpressionParser() {
    @Override
    public IStandardExpression parseExpression(final IExpressionContext context, final String input) {
        if (!input.startsWith("${") || !input.endsWith("}")) {
            throw new IllegalArgumentException("Only variable expressions allowed, not " + input);
        }
        final String[] path = StringUtils.split(input.substring("${".length(), input.length() - "}".length()), '.');
        return new IStandardExpression() {
            @Override
            public String getStringRepresentation() {
                return "Variable " + Arrays.toString(path);
            }

            @Override
            public Object execute(final IExpressionContext context) {
                Object result = context.getVariable(path[0]);
                for (int i = 1; i < path.length; i++) {
                    try {
                        result = BeanUtils.getProperty(result, path[i]);
                    } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                        throw new Error(e);
                    }
                }
                return result;
            }

            @Override
            public Object execute(final IExpressionContext context, final StandardExpressionExecutionContext expContext) {
                return execute(context);
            }
        };
    }
});
templateEngine.setDialect(dialect);
System.out.println(templateEngine.process(
    "<html xmlns:th=\"http://www.thymeleaf.org\"><p th:text=\"${someVar}\"></p></html>",
    new Context(Locale.ENGLISH, Collections.singletonMap("someVar", "someValue"))
));

它看起来有效,但这还够吗?还是有其他安全漏洞?

1 个答案:

答案 0 :(得分:0)

我认为使用Java Security Manager可以更好地解决您的用例。您将能够为负责加载,解析和解释用户模板的代码提供非常狭窄的权限。