FlawOpen

flawopen.com/Vulnerabilities/Server-Side Template Injection (SSTI)

Server-Side Template Injection (SSTI): Ursache und Schutz

Impact depends on reachable template behavior CWE-1336 Template Engine Security
💡 Einfach erklärt — Daten oder Druckeranweisungen

Stellen Sie sich ein Versandunternehmen vor, das Briefe mit der Vorlage „Hallo, {{ name }}“ druckt. Sicher ist: Der Drucker erhält die feste Vorlage und den Kundennamen als Daten. Unsicher ist: Der Kundentext wird vor dem Druck in die Vorlagenanweisungen eingefügt. Interpretiert die Template-Engine diesen Text als Template-Syntax, liegt Server-Side Template Injection vor. Die möglichen Folgen hängen von Engine, Konfiguration, verfügbaren Objekten und Prozessrechten ab; die Auswertung eines Ausdrucks bedeutet nicht automatisch, dass Systembefehle ausgeführt werden.

Ziel: Erstellung von Template-Quelltext und serverseitiges Rendering mit Engines wie Jinja, Twig, FreeMarker und ERB.
Verwundbare Grenze: Nicht vertrauenswürdige Eingaben werden als Template-Quelltext kompiliert oder geparst, statt einer vertrauenswürdigen Vorlage als Wert übergeben zu werden.
Auswirkung: Auswertung von Template-Ausdrücken; weitere Folgen hängen von Engine-Funktionen, exponierten Objekten, Sandbox und Prozessrechten ab.
Abhilfe: Quelltext vertrauenswürdig und statisch halten; Benutzereingaben nur als Kontextdaten übergeben. Von Nutzern erstellte Templates bei Bedarf isoliert rendern.

Grundbegriffe und Subsystem-Terminologie

Template-Engine
Serverkomponente wie Jinja oder Twig, die Template-Syntax parst und aus Vorlage und Kontextdaten eine Ausgabe erzeugt.
Template-Quelltext-Injection
Fehler, bei dem externer Text vor dem Parsen in den Quelltext eingefügt und deshalb als Template-Syntax statt als Daten interpretiert wird.
Kontextdaten
Werte, die getrennt an ein festes, vertrauenswürdiges Template übergeben werden. Diese Trennung verhindert, dass ein Wert wie {{ 7 * 7 }} erneut als Quelltext geparst wird.
CWE-1336
Unzureichende Neutralisierung spezieller Elemente in einer Template-Engine. Beschreibt die unsichere Verarbeitung externer Eingaben als Template-Syntax.

Schrittweiser Angriffsablauf

Step 1

Angreiferkontrollierte Eingabe erreicht einen Template-Sink

Ein Formularfeld, gespeicherter Profilwert oder anderer extern beeinflusster Text erreicht Code, der ein Template erstellt oder kompiliert. Verwundbar ist die Quelltexterstellung, nicht das bloße Rendern eines Werts.

Step 2

Die Anwendung vermischt Daten und Template-Anweisungen

Die Anwendung interpoliert den nicht vertrauenswürdigen Text in den Template-Quelltext (etwa als f-String für render_template_string), statt eine statische Vorlage mit separatem Kontextwert zu verwenden.

Step 3

Die Engine parst den kombinierten Quelltext

Die Engine interpretiert Ausdrücke gemäß ihrer Sprache und Konfiguration. Ein harmloser Rechenausdruck kann die Auswertung zeigen; er beweist allein keinen Zugriff auf Dateien, Geheimnisse oder Systembefehle.

Step 4

Die Auswirkung hängt von Engine und Bereitstellung ab

Weitere Folgen hängen von zugänglichen Objekten und Funktionen, Sandbox-Verhalten, Engine-Beschränkungen und den Rechten des Webprozesses ab. RCE ist in manchen Konfigurationen möglich, aber keine automatische Folge jeder SSTI.

Mechanismus und Ursache

SSTI entsteht, wenn extern beeinflusster Text vor dem Parsen Teil des Template-Programms wird. Bei Flask/Jinja besteht das verwundbare Muster darin, aus Request-Daten neuen Quelltext zu erzeugen und an render_template_string() zu übergeben. HTML-Escaping schützt die Ausgabe und macht nicht vertrauenswürdigen Template-Quelltext nicht zu Daten. Die Abhilfe lädt eine feste Vorlage und übergibt den Wert separat als Kontext. Wenn Nutzer Templates erstellen dürfen, stellen Sie nur ein minimales Datenmodell bereit und rendern Sie in einem isolierten Worker mit Ressourcenlimits. Eine Sandbox ist zusätzliche Verteidigung, kein Grund, Geheimnisse oder mächtige Anwendungsobjekte offenzulegen.

flask_app.py (Unsicheres Muster)Unsicher
# VULNERABLE: request data becomes template source before parsing.
from flask import Flask, request, render_template_string
app = Flask(__name__)

@app.route("/greet")
def greet():
    name = request.args.get("name", "Guest")
    # A value such as {{ 7 * 7 }} is interpreted by the template engine.
    source = f"<h1>Welcome, {name}!</h1>"
    return render_template_string(source)
flask_app.py (Abgesichert)Abgesichert
# HARDENED: fixed template source; request data stays a context value.
from flask import Flask, request, render_template
app = Flask(__name__)

@app.route("/greet")
def greet():
    name = request.args.get("name", "Guest")
    return render_template("greet.html", name=name)

# templates/greet.html is trusted, static source:
# <h1>Welcome, {{ name }}!</h1>

Angriffssequenz und konzeptionelles Beispiel

Technische Regeln für Prävention und Schutz

Primärquellen und verwandte Sicherheitsthemen:Vollständiges Sicherheitsverzeichnis →
CWE-1336: Template-Engine-Injection → OWASP WSTG: Server-Side Template Injection → Jinja: Sandbox und Sicherheitshinweise → Jinja-API: Templates und Loader → Flask: Template-Rendering →