FlawOpen

flawopen.com/SSTI/Jinja2

render_template_string() de Jinja2 est-il sûr ?

CWE-1336: Injection de modèle côté serveurPage de référence
Réponse courte

N’utilisez render_template_string() que si le code de l’application contrôle la chaîne du modèle. Si une entrée non fiable est insérée dans cette chaîne avant son analyse par Jinja, il s’agit d’une SSTI. Dans l’environnement Jinja par défaut et non sandboxé de Flask, l’impact peut inclure l’exécution de code selon les objets accessibles, la configuration et l’application ; ce résultat n’est pas automatique dans tous les déploiements.

VULNÉRABLE
# All four are the same bug
render_template_string(f"Hi {name}")
render_template_string("Hi " + name)
render_template_string("Hi %s" % name)
render_template_string("Hi {}".format(name))

# A very common real-world shape:
@app.errorhandler(404)
def not_found(e):
    return render_template_string(
        f"<h1>No such page: "
        f"{request.path}</h1>"
    ), 404
# The URL path is attacker-controlled.
CORRIGÉ
# Template is a literal; the user value
# arrives as a named context variable
render_template_string(
    "Hi {{ name }}", name=name
)

# Better still, a real template file
render_template("greeting.html",
                name=name)

# For the 404 case, no template
# evaluation is needed at all:
return render_template("404.html",
                       path=request.path), 404

Pourquoi une source de modèle contrôlée par un attaquant est risquée

Par défaut, Flask expose aux modèles des variables globales de l’application telles que config, request et session. Si un attaquant contrôle la source du modèle, Jinja évalue ses expressions avec les objets accessibles dans cet environnement. L’impact dépend des objets et capacités exposés par l’application. Une expression arithmétique inoffensive peut confirmer l’évaluation, mais ne prouve à elle seule ni l’exécution de code ni les données accessibles.

Un modèle peut exposer des valeurs sensibles si l’application les a placées dans le contexte. Par exemple, config de Flask peut contenir SECRET_KEY ou des paramètres de base de données, mais chaque déploiement diffère. Ne placez pas de secrets dans les données accessibles aux modèles et ne confondez pas l’échappement de sortie avec une protection contre l’évaluation du modèle.

CVE-2024-56201 est un cas distinct

Cette vulnérabilité du compilateur Jinja est distincte d’une SSTI classique et n’est pas nécessaire à celle-ci : CVE-2024-56201 concerne Jinja 3.0.0 à 3.1.4 lorsqu’un attaquant contrôle à la fois le contenu et le nom du modèle. Dans ce cas, l’exécution de code Python arbitraire était possible même avec le sandbox. Jinja 3.1.5 corrige le problème. Consultez l’avis et mettez à niveau si votre application accepte des modèles ou noms fournis par des attaquants.

Où ce problème apparaît

On le rencontre dans des pages d’erreur qui reflètent le chemin demandé, des fonctions d’administration de modèles d’e-mail, la personnalisation par client et des points de prévisualisation ou de débogage qui n’auraient pas dû être exposés.

Questions fréquentes

L’autoescape protège-t-il contre cela ?

Non. L’autoescape échappe les valeurs rendues afin de réduire les risques de XSS en sortie. Il n’empêche pas la compilation d’une chaîne utilisateur comme source de modèle. Ces contrôles s’appliquent à des étapes différentes.

Et si je dois accepter des modèles fournis par les utilisateurs, par exemple pour personnaliser des e-mails ?

Jinja fournit SandboxedEnvironment pour les modèles utilisateurs, mais sa documentation précise que ce n’est pas une sécurité parfaite. Ne transmettez que les données nécessaires, évitez les objets à effets de bord et imposez des limites CPU, mémoire et processus en dehors du moteur. Le sandbox ne sécurise pas l’interpolation d’une entrée non fiable avant l’analyse du modèle.

Comment trouver ce problème dans un code existant ?

Recherchez render_template_string et vérifiez que son premier argument est une chaîne fixe contrôlée par l’application. Transmettez les valeurs utilisateur comme variables de contexte nommées ou utilisez un fichier de modèle. Examinez aussi les API qui compilent des modèles dynamiquement et permettent de contrôler leurs noms.

Références

À voir aussi SSTI : cause et correction de l’injection de templates Qu’est-ce que l’injection de template côté serveur ? SSTI FreeMarker et Velocity : sécuriser les modèles