flawopen.com/Vulnerabilities/Server-Side Template Injection (SSTI)
Server-Side Template Injection (SSTI): causa y corrección
Imagina una empresa que imprime cartas con la plantilla “Hola, {{ name }}”. El proceso seguro entrega a la impresora una plantilla fija y el nombre del cliente como dato. El proceso inseguro inserta el texto del cliente en las instrucciones de la plantilla antes de procesarla. Si el motor interpreta ese texto como sintaxis de plantilla, existe Server-Side Template Injection. El impacto depende del motor, su configuración, los objetos disponibles y los privilegios del proceso; evaluar una expresión no implica ejecutar comandos del sistema.
Conceptos clave y términos del subsistema
- Motor de plantillas
- Componente del servidor, como Jinja o Twig, que analiza sintaxis de plantillas y genera salida a partir de una plantilla y datos de contexto.
- Inyección en el código fuente de la plantilla
- Fallo por el que texto externo se incluye en el código fuente antes del análisis, de modo que el motor lo interpreta como sintaxis y no como dato.
- Datos de contexto
- Valores pasados por separado a una plantilla fija y confiable. La separación correcta evita que un valor como
{{ 7 * 7 }}se vuelva a analizar como código fuente. - CWE-1336
- Neutralización incorrecta de elementos especiales usados en un motor de plantillas. Describe el procesamiento inseguro de entrada externa como sintaxis de plantilla.
Flujo de ataque paso a paso
La entrada controlada por el atacante llega a un punto de plantilla
Un campo, valor de perfil almacenado u otra cadena influida externamente llega al código que crea o compila una plantilla. El fallo está en construir el código fuente, no en renderizar un valor.
La aplicación mezcla datos e instrucciones de plantilla
La aplicación interpola la cadena no confiable en el código fuente (por ejemplo, una f-string enviada a render_template_string) en lugar de usar una plantilla estática y un valor de contexto separado.
El motor analiza el código combinado
El motor interpreta las expresiones según su lenguaje y configuración. Una expresión aritmética inocua puede demostrar la evaluación; eso por sí solo no demuestra acceso a archivos, secretos o comandos del sistema.
El impacto depende de las capacidades y el despliegue
El impacto adicional depende de los objetos y funciones accesibles, el sandbox, las restricciones del motor y los privilegios del proceso web. RCE es posible en algunas configuraciones, pero no es consecuencia automática de todo SSTI.
Mecanismo y causa raíz
SSTI ocurre cuando la aplicación permite que texto influido externamente forme parte del programa de plantilla antes de analizarlo. En Flask/Jinja, el patrón vulnerable crea una nueva cadena de código fuente con datos de la petición y la pasa a render_template_string(); el escape HTML protege la salida y no convierte código fuente no confiable en datos. La corrección carga una plantilla fija y pasa el valor por separado como contexto. Si los usuarios deben crear plantillas, expón un modelo de datos mínimo y renderízalas en un worker aislado con límites de recursos. El sandbox aporta defensa en profundidad, pero no justifica exponer secretos u objetos potentes.
# 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)
# 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>
Secuencia de ataque y ejemplo conceptual
- 1Origen: Un valor influido externamente llega a una ruta que construye plantillas.
- 2Composición insegura: La aplicación introduce ese valor en el código fuente de la plantilla en vez de pasarlo por separado como dato de contexto.
- 3Interpretación: El motor analiza el código combinado. En una prueba autorizada, una expresión aritmética inocua puede confirmar la evaluación.
- 4Impacto condicionado: El acceso posterior depende del motor, los objetos expuestos, la configuración y los privilegios; no deduzcas RCE solo porque se evalúe una expresión.
Reglas de prevención y protección de ingeniería
- ✓Mantén fijo el código fuente: Carga plantillas confiables desde archivos o un loader controlado; pasa la entrada del usuario solo como dato de contexto. No concatentes datos de la petición en el código fuente.
- ✓Distingue SSTI de inyección HTML: El escape HTML protege los contextos de salida; no corrige un flujo en el que entrada no confiable se analiza como código de plantilla.
- ✓Restringe las plantillas de usuario: Si esa función es necesaria, usa el sandbox del motor para ese fin, expón un modelo mínimo de datos y renderiza en un worker aislado con límites de recursos. Sigue las notas de seguridad del motor.
- ✓Limita el impacto: Ejecuta el renderizador como servicio sin privilegios y con acceso mínimo a archivos, red y secretos. Es contención, no la corrección principal.
- ✓Añade pruebas de regresión: Pasa una marca inocua como
{{ 7 * 7 }}como dato y comprueba que siga siendo dato; verifica también que las plantillas procedan solo del loader confiable.