Su código en la mira: por qué la seguridad en TypeScript no es una opción, sino una necesidad
\n\n¿Alguna vez se ha preguntado qué sucede cuando un usuario escribe en el campo de búsqueda de su sitio no solo "libros de Python", sino algo como '; DROP TABLE users; --? Si su backend en TypeScript no está preparado para tal eventualidad, no solo corre el riesgo de obtener un error, sino de perder toda su base de datos. ¿Suena como el guión de una película de terror? Bienvenido al mundo real del desarrollo web, donde la seguridad en TypeScript no es una característica de moda, sino una higiene básica del código.
En este artículo no daremos aburridas conferencias. Analizaremos a los dos principales enemigos de cualquier aplicación web: las inyecciones SQL y el XSS (Cross-Site Scripting). Aprenderá cómo los hackers atacan sus proyectos y, lo más importante, cómo convertir su código TypeScript en una fortaleza inexpugnable con ejemplos reales y las mejores prácticas.
\n\nInyecciones SQL: cómo los atacantes "hablan" con su base de datos
\n\nImagine que su aplicación es un conserje educado que cumple cualquier petición de un huésped. Si el huésped pide: "Muestre la habitación nº 5", el conserje la muestra. Pero, ¿y si el huésped pide: "Muestre todas las habitaciones y deme las llaves de la caja fuerte"? Sin verificación, el conserje también lo haría. Una inyección SQL funciona exactamente así: el atacante "incrusta" sus comandos en una entrada de usuario normal.
\n\nSupongamos que tiene una consulta simple para buscar un usuario por nombre:
\n\n// ❌ PELIGROSO: código vulnerable\nconst userName = req.body.username; // el usuario ingresó "admin"\nconst query = `SELECT * FROM users WHERE name = '${userName}'`;\ndb.execute(query);\n\n¿Parece inofensivo? Ahora imagine que el usuario ingresa: admin' OR '1'='1. La consulta se convierte en:
SELECT * FROM users WHERE name = 'admin' OR '1'='1'\n\n¡Felicidades! Acaba de entregar al atacante la lista de todos los usuarios del sistema. ¿Y si quiere eliminar algo? Fácil: admin'; DROP TABLE users; -- — y su base de datos ya no existe.
Cómo protegerse: las consultas parametrizadas son su escudo
\n\nLa regla principal para la protección contra inyecciones SQL en TypeScript: nunca inserte datos de usuario directamente en una cadena de consulta. Utilice consultas parametrizadas (prepared statements). Estas separan el código SQL de los datos, y la base de datos trata la entrada del usuario exclusivamente como datos, no como comandos.
\n\nEjemplo con la librería pg (para PostgreSQL):
// ✅ SEGURO: consulta parametrizada\nimport { Pool } from 'pg';\n\nconst pool = new Pool({\n connectionString: process.env.DATABASE_URL\n});\n\nasync function getUserByName(userName: string): Promise<any> {\n const query = 'SELECT * FROM users WHERE name = $1';\n const result = await pool.query(query, [userName]);\n return result.rows;\n}\n\n// Uso\nconst userInput = req.body.username; // incluso si es "admin' OR '1'='1"\nconst user = await getUserByName(userInput);\n// La base de datos lo tratará como la búsqueda de un usuario con ese extraño nombre\nconsole.log(user); // [] — no se encontró nada\n\nEl mismo principio funciona con otros ORM, como Prisma o TypeORM. Por defecto, utilizan consultas parametrizadas, lo que convierte la seguridad en TypeScript en una función integrada.
\n\n// ✅ SEGURO: usando Prisma\nimport { PrismaClient } from '@prisma/client';\n\nconst prisma = new PrismaClient();\n\nasync function findUser(name: string) {\n return prisma.user.findUnique({\n where: { name: name } // Prisma escapa los datos de entrada automáticamente\n });\n}\n\nAtaques XSS: cuando su sitio comienza a transmitir código ajeno
\n\nSi las inyecciones SQL atacan la base de datos, el XSS (Cross-Site Scripting) ataca a sus usuarios. Imagine que un atacante