Los problemas de seguridad pueden llevar a la fuga de datos de los usuarios o incluso a la destrucción total del sitio. Las investigaciones muestran que la mayoría de los sitios tienen problemas de seguridad y son vulnerables a los ataques. De vez en cuando, se producen hackeos y fugas de datos de cientos de miles y millones de usuarios.
La seguridad de las aplicaciones web es un tema importante al que dedicaremos toda esta lección.
La regla principal de seguridad
Suena así:
Nunca confíes en los usuarios
En primer lugar, esta regla se refiere a los datos ingresados por los usuarios en el sitio. Supongamos que tenemos una página de perfil de usuario, donde se muestra su identificador, tomado de la URL:
import fastify from 'fastify';
const app = fastify();
const port = 3000;
app.get('/users/:id', (req, res) => {
res.type('html');
res.send(`<h1>${req.params.id}</h1>`);
});
app.listen({ port }, () => {
console.log(`Example app listening on port ${port}`);
});
Cuando el código implementa esta función, asume que solo se usan nombres validos en la dirección. Ahora intentemos abrir esta dirección:
http://localhost:3000/users/%3Cscript%3Ealert('attack!')%3B%3C%2Fscript%3E
Si confiamos en los datos de los usuarios y abrimos esta dirección, sucederá esto:
Esta dirección tiene codificadoun código JavaScript, que originalmente se veía así:
<script>
alert('attack!');
</script>
El problema es que el código no se mostró, pero terminó en el HTML de la página y se ejecutó. Esto sucedió porque para el navegador este código JavaScript se ve como parte de la página.
Si abres el HTML resultante, se verá así:
<h1>
<script>alert('attack!');</script>
</h1>
Así es como ocurre un ataque XSS (Cross-site Scripting). El código malicioso se inyecta en la página, se ejecuta en el navegador del usuario y envía información sobre el usuario al servidor del atacante. XSS es uno de los ataques más comunes. Muchos sitios de grandes empresas tienen estas vulnerabilidades.
La peculiaridad de tales ataques es que el código malicioso puede utilizar la autorización del usuario en el sistema web. Así, el atacante puede obtener acceso avanzado al sistema o los nombres de usuario y contraseñas de los usuarios. Si en el código fuente se encuentra una construcción <texto>, el navegador automáticamente la considera una etiqueta.
Volviendo al código anterior:
import fastify from 'fastify';
const app = fastify();
const port = 3000;
app.get('/users/:id', (req, res) => {
res.type('html');
res.send(`<h1>${req.params.id}</h1>`);
});
app.listen({ port }, () => {
console.log(`Example app listening on port ${port}`);
});
Aquí estamos mostrando datos sin ningún tipo de procesamiento previo. En este caso, el navegador intenta interpretar como HTML todo lo que parece HTML. Cualquier usuario podría inyectar código JavaScript ejecutable en el sitio sin nuestro consentimiento. En otras palabras, hemos confiado en los datos del usuario y hemos creado una vulnerabilidad.
Para corregirlo, necesitamos utilizar no las etiquetas mismas, sino los equivalentes de los caracteres en HTML. Entonces, el código anterior comenzará a lucir así:
<h1>
<script>alert('attack!');</script>
</h1>
Aquí hemos reemplazado:
<por<>por>
Esto no es escapar, sino reemplazar los caracteres especiales por sus equivalentes en HTML. Si abres el navegador, verás la representación correcta:
El reemplazo de caracteres por caracteres especiales se realiza con bibliotecas especiales, como sanitize-html. Una de las opciones se ve así:
# Instalación del paquete
npm i sanitize-html
import fastify from 'fastify';
import sanitize from 'sanitize-html';
const app = fastify();
const port = 3000;
app.get('/users/:id', (req, res) => {
const escapedId = sanitize(req.params.id);
res.type('html');
res.send(`<h1>${escapedId}</h1>`);
});
app.listen({ port }, () => {
console.log(`Example app listening on port ${port}`);
});
La función sanitize() toma HTML como entrada y reemplaza en él todos los caracteres especiales por sus equivalentes en HTML. Los demás caracteres permanecen sin cambios.
Todos los datos que mostramos deben pasar por este procesamiento. La única excepción son las situaciones en las que sabemos con certeza que los datos contienen HTML y queremos mostrarlo. Estos datos pueden incluir artículos de blog, ya que contienen una parte de HTML.
Trabajo independiente
- Agrega al aplicativo una ruta que muestre el identificador del usuario basándose en los datos de la línea de solicitud.
- Repite los pasos de la lección.
- Protege la salida del identificador del usuario en la página del usuario de la misma manera que se hizo en la teoría de la lección.
- Asegúrate de que el motor de plantillas protege contra los ataques XSS. Modifica el controlador de tal manera que los datos no escapados del usuario se envíen a la plantilla y se realice su procesamiento.
- Inicia la aplicación y trata de pasar algún HTML en la línea de solicitud.
- Verifica que los datos en la plantilla pasan por un procesamiento previo de forma automática.
Para acceder completo a curso necesitas un plan básico
El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.