Tabla de Estrategias de Escape
[sanitize]
| Filtro | Alias | Uso | Ejemplo de entrada | Ejemplo de salida | Cuándo usarlo |
|---|---|---|---|---|---|
| |e | |e('html') | |escape | Escape HTML | <script>alert('XSS')</script> | <script>alert('XSS')</script> | Contenido HTML general: títulos, párrafos, texto visible |
| |e('html_attr') | - | Escape atributos HTML | " onclick="alert('XSS') | " onclick="alert('XSS') | Dentro de atributos HTML: <div title="{{ var|e('html_attr') }}"> |
| |e('js') | - | Escape JavaScript | '; alert('XSS'); var x=' | \'; alert(\'XSS\'); var x=\' | Dentro de código JavaScript: var name = '{{ var|e('js') }}'; |
| |e('css') | - | Escape CSS | </style><script>alert()</script> | \3C \2F style\3E \3C script\3E ... | Dentro de código CSS: color: {{ var|e('css') }}; |
| |e('url') | |url_encode | Escape URL | hello world & más | hello%20world%20%26%20m%C3%A1s | Parámetros de URL: ?search={{ query|e('url') }} |
[/sanitize]
Ejemplos Prácticos
1. HTML - Contenido visible
{# ✅ CORRECTO #}
<h1>{{ page.title|e }}</h1>
<p>{{ page.content|raw }}</p>
{# ❌ INCORRECTO (vulnerable a XSS) #}
<h1>{{ page.title }}</h1>
2. HTML Attributes - Dentro de atributos
{# ✅ CORRECTO #}
<img src="logo.png" alt="{{ page.title|e('html_attr') }}">
<input type="text" value="{{ user_input|e('html_attr') }}">
<div data-content="{{ description|e('html_attr') }}">
{# ❌ INCORRECTO (|e solo no es suficiente en atributos) #}
<img alt="{{ page.title|e }}">
3. JavaScript - Dentro de scripts
{# ✅ CORRECTO #}
<script>
var title = '{{ page.title|e('js') }}';
var data = {{ json_data|json_encode|raw }};
</script>
{# ❌ INCORRECTO #}
<script>
var title = '{{ page.title|e }}'; // No previene inyección JS
</script>
4. CSS - Dentro de estilos
{# ✅ CORRECTO #}
<style>
.custom {
background-color: {{ user_color|e('css') }};
}
</style>
{# ⚠️ MEJOR: Validar colores antes #}
{% if user_color matches '/^#[0-9A-F]{6}$/i' %}
<style>.custom { background-color: {{ user_color }}; }</style>
{% endif %}
5. URL - Parámetros de consulta
{# ✅ CORRECTO #}
<a href="/search?q={{ search_term|e('url') }}&category={{ category|e('url') }}">
Buscar
</a>
{# ✅ También correcto #}
<a href="/search?q={{ search_term|url_encode }}">Buscar</a>
{# ❌ INCORRECTO #}
<a href="/search?q={{ search_term }}"> {# Rompe con espacios y caracteres especiales #}
Casos Especiales
Escape doble (evitar)
{# ❌ MAL - Escape doble #}
{% set title = page.title|e %}
<h1>{{ title|e }}</h1>
{# Resultado: &lt;script&gt; (doblemente escapado) #}
{# ✅ BIEN - Escapar una sola vez #}
{% set title = page.title %}
<h1>{{ title|e }}</h1>
Contenido HTML confiable (raw)
{# Si el contenido YA está procesado y es seguro #}
<div>{{ page.content|markdown|raw }}</div>
{# ⚠️ NUNCA uses |raw con input del usuario sin sanitizar #}
JSON en JavaScript
{# ✅ CORRECTO - json_encode ya escapa correctamente #}
<script>
var config = {{ settings|json_encode|raw }};
</script>
{# ❌ INCORRECTO #}
<script>
var config = {{ settings|e('js') }}; // No convierte a JSON válido
</script>
Resumen de Mejores Prácticas
- Por defecto usa
|epara todo contenido HTML visible - Usa
|e('html_attr')dentro de atributos HTML - Usa
|e('js')dentro de strings JavaScript - Usa
|e('url')en parámetros de URL - Evita
|rawa menos que el contenido sea 100% confiable - Escapa una sola vez - al final, en el output
- Para JSON usa
|json_encode|raw, no|e('js')