flawopen.com/SSTI/FreeMarker und Velocity
Sind FreeMarker- und Velocity-Vorlagen mit Benutzereingaben sicher?
Benutzerwerte bleiben Daten, wenn sie in eine vertrauenswürdige Vorlage eingesetzt werden. Vom Benutzer kontrollierter Vorlagencode ist etwas anderes: Er erlaubt Ausdrücke in der Vorlagensprache. Die erreichbaren Fähigkeiten hängen von Version, Wrapper oder Uberspector, Modellobjekten und Anwendungsrechten ab. Gehen Sie nicht davon aus, dass jede Template Injection Betriebssystembefehle ausführt. Behandeln Sie nicht vertrauenswürdigen Vorlagencode als ausführbare Logik und rendern Sie ihn außerhalb des Anwendungsprozesses.
// Risiko: Anfragewerte als Vorlagenquelltext parsen String src = "Hello " + userSuppliedName; Template t = new Template("t", src, cfg); t.process(model, writer); // Risiko: benutzergesteuerte VTL-Zeichenfolge auswerten Velocity.evaluate(context, writer, "log", userTemplate);
// Vertrauenswürdige Classpath-Vorlage; Modell nur mit Skalaren 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: vertrauenswürdige Vorlage und begrenzte Introspektion (Tiefenverteidigung) 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);
Warum Java-Vorlagen gefährliche Fähigkeiten offenlegen können
Vorlagen werten Ausdrücke anhand eines Datenmodells aus; welche Java-Funktionen erreichbar sind, hängt aber von der Konfiguration ab. FreeMarkers Standard-Wrapper kann JavaBean-Eigenschaften und -Methoden beliebiger POJOs offenlegen; die verfügbaren Mitglieder richten sich nach Wrapper und Zugriffsrichtlinie. Velocitys Standard-Uberspect ordnet VTL-Eigenschaften öffentlichen Java-Methoden zu. Das bedeutet nicht, dass jedes Modell uneingeschränkte Reflection ermöglicht: Das Risiko steigt, wenn Dienste, ClassLoader, Request-Objekte oder andere mächtige Fähigkeiten im Modell liegen. Verwenden Sie bevorzugt Maps mit Strings und einfachen Werten und geben Sie nur benötigte Felder frei.
FreeMarkers Built-in ?new kann Klassen instanziieren, die TemplateModel implementieren. Apache empfiehlt eine eingeschränkte Klassenauflösung für hochgeladene Vorlagen; SAFER_RESOLVER erlaubt weiterhin bestimmte Klassen, während ALLOWS_NOTHING_RESOLVER jede Auflösung verweigert. Das ersetzt weder einen eingeschränkten Wrapper noch ein minimales Datenmodell.
Risiko senken und Grenzen kennen
- ✓FreeMarker: Setzen Sie für nicht vertrauenswürdige Vorlagen
new_builtin_class_resolveraufALLOWS_NOTHING_RESOLVERund verwenden Sie einen Wrapper wieSimpleObjectWrapper, der beliebige POJOs ablehnt. Übergeben Sie nur einfache, zweckgebundene Werte. - ✓Velocity: Verwenden Sie bei nicht vertrauenswürdigen Vorlagen
SecureUberspectorund geben Sie dem Kontext nur benötigte einfache Werte. Er sperrt dokumentierte Reflection- und Objekterzeugungspfade, ist aber keine Betriebssystem-Sandbox. - ✓Beide: Laden Sie Anwendungsvorlagen aus einer vertrauenswürdigen, manipulationsgeschützten Quelle. Machen Sie niemals Request-Parameter oder benutzerveränderbare Datenbankzeilen zu Vorlagenquelltext.
- ✓Wenn benutzerverfasste Vorlagen Produktanforderung sind: Rendern Sie sie in einem separaten Prozess mit minimalen Rechten und ohne Netzwerk, Geheimnisse oder beschreibbare Anwendungsdateien. Begrenzen Sie CPU, Speicher und Laufzeit außerhalb des Motors.
Verstehen Sie Motoreinschränkungen als Tiefenverteidigung, nicht als Prozessisolation. Verwenden Sie unterstützte Versionen, prüfen Sie die genaue Konfiguration anhand aktueller Herstellerhinweise und halten Sie Geheimnisse sowie privilegierte Objekte vom Renderer fern.
Häufige Fragen
Das ist ein verwandtes, aber eigenständiges Risiko. Ein benutzergesteuerter View-Name ist nicht automatisch eine Expression-Injection. Prüfen Sie den konkreten Datenfluss in die Thymeleaf- oder Spring-Expression-Language-Auswertung und erzeugen Sie keine Ausdrucksfragmente aus nicht vertrauenswürdigen Eingaben. Halten Sie Integrationen aktuell und wählen Sie Views über vertrauenswürdige Anwendungslogik.
Vorlagenautoren können die Fähigkeiten des Motors und Datenmodells nutzen; das bedeutet nicht immer Betriebssystembefehle ausführen zu können. Behandeln Sie das Bearbeitungsrecht als sensibles Code-Autorenprivileg, beschränken Sie es auf vertrauenswürdige Maintainer und protokollieren Sie Änderungen.
Ein logikloser Motor wie Mustache kann die Oberfläche für Ausdrücke und Methodenaufrufe verkleinern. Ausgabekodierung, Kontrolle der Vorlagenquelle und Fähigkeiten von Helfern bleiben trotzdem wichtig. Wählen Sie einen Motor für dieses Vertrauensmodell und isolieren Sie das Rendering, statt einen allgemeinen JVM-Motor als Sandbox zu verwenden.
Offizielle Quellen und Referenzen
- Apache FreeMarker — FAQ zur Sicherheit hochgeladener Vorlagen
- Apache FreeMarker — SimpleObjectWrapper-API
- Apache FreeMarker — TemplateClassResolver-API
- Apache Velocity — Entwicklerhandbuch
- Apache Velocity 2.3 — ClasspathResourceLoader-API
- PortSwigger — Server-Side Template Injection
- CWE-1336 — Server-Side Template Injection