FlawOpen

flawopen.com/SSTI/FreeMarker e Velocity

FreeMarker e Velocity são seguros com entrada do usuário?

CWE-1336: Server-Side Template InjectionPágina de referência
Resposta curta

Valores fornecidos pelo usuário continuam sendo dados quando inseridos em um template confiável. Já permitir que o usuário controle o código-fonte do template permite escrever expressões na linguagem do mecanismo. O alcance depende da versão, do wrapper ou introspector, dos objetos no modelo e das permissões da aplicação. Não presuma que toda injeção de template executa comandos do sistema; trate código de template não confiável como lógica executável e mantenha sua renderização fora do processo da aplicação.

VULNERÁVEL
// Risco: analisar entrada da requisição como template
String src = "Hello " + userSuppliedName;
Template t = new Template("t", src, cfg);
t.process(model, writer);

// Risco: avaliar uma string VTL controlada pelo usuário
Velocity.evaluate(context, writer,
                  "log", userTemplate);
CORRIGIDO
// Template confiável do classpath; modelo só com escalares
Configuration cfg = new Configuration(
    Configuration.VERSION_2_3_34);
cfg.setTemplateLoader(new ClassTemplateLoader(
    App.class, "/templates"));
cfg.setNewBuiltinClassResolver(
    TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);
cfg.setObjectWrapper(new SimpleObjectWrapper(
    Configuration.VERSION_2_3_34));
Template t = cfg.getTemplate("hello.ftl");
Map<String,Object> model = Map.of(
    "name", userSuppliedName);
t.process(model, writer);

// Velocity: template confiável e introspecção restrita (defesa em profundidade)
Properties p = new Properties();
p.setProperty("resource.loaders", "class");
p.setProperty("resource.loader.class.class",
    ClasspathResourceLoader.class.getName());
p.setProperty("runtime.introspector.uberspect",
    SecureUberspector.class.getName());
VelocityEngine engine = new VelocityEngine();
engine.init(p);
Template vt = engine.getTemplate("hello.vm", "UTF-8");
VelocityContext vc = new VelocityContext();
vc.put("name", userSuppliedName);
vt.merge(vc, writer);

Por que mecanismos Java podem expor capacidades perigosas

Os templates avaliam expressões sobre um modelo de dados, mas a superfície Java disponível depende da configuração. O wrapper padrão do FreeMarker pode expor propriedades e métodos JavaBean de POJOs arbitrários; os membros acessíveis dependem do wrapper e da política de acesso. O Uberspect padrão do Velocity mapeia propriedades VTL para métodos Java públicos. Isso não significa que qualquer modelo dê acesso irrestrito à reflexão: o risco aumenta quando o modelo contém objetos de serviço, carregadores de classes, objetos de requisição ou outras capacidades poderosas. Prefira mapas de strings e valores simples e exponha apenas os campos necessários a cada template confiável.

O built-in ?new do FreeMarker pode instanciar classes que implementam TemplateModel. O Apache recomenda restringir a resolução de classes para templates enviados por usuários; SAFER_RESOLVER ainda permite algumas classes, enquanto ALLOWS_NOTHING_RESOLVER nega toda resolução. Esse controle não substitui um wrapper restrito e um modelo de dados mínimo.

Como reduzir o risco e conhecer os limites

Trate as restrições do mecanismo como defesa em profundidade, não como isolamento de processo. Use versões suportadas, confira a configuração exata na orientação atual do mecanismo e mantenha o renderizador longe de segredos e objetos privilegiados.

Perguntas frequentes

Thymeleaf também é afetado?

É um risco relacionado, mas distinto. Um nome de view controlado pelo usuário não é automaticamente uma falha de injeção de expressão. Verifique o fluxo de dados específico até a avaliação de Thymeleaf ou Spring Expression Language e não construa fragmentos de expressão com entrada não confiável. Mantenha as integrações atualizadas e selecione views pela lógica confiável da aplicação.

Só administradores podem editar templates. Isso é aceitável?

Autores de templates podem usar as capacidades expostas pelo mecanismo e pelo modelo de dados; isso nem sempre significa execução de comandos do sistema operacional. Trate a permissão de editar templates como privilégio sensível de autoria de código, restrinja-a a mantenedores confiáveis e registre as alterações.

Qual mecanismo é mais seguro para templates enviados por usuários?

Um mecanismo sem lógica, como Mustache, pode reduzir a superfície de expressões e chamadas de métodos, mas codificação da saída, controle da origem dos templates e capacidades dos helpers continuam importantes. Escolha um mecanismo projetado para esse modelo de confiança e isole a renderização; não use um mecanismo JVM de uso geral como sandbox.

Fontes oficiais e referência

Veja também SSTI: causa, impacto e correção de template injection O render_template_string() do Jinja2 é seguro? O que é injeção de template no servidor?