security

Security herramientas

Las tareas de seguridad del día a día en ingeniería web — hashes, entropía de contraseñas, reclamaciones de JWT, redacción de CSP y censura de capturas antes de compartirlas — y qué herramienta encaja en cada trabajo.

11 herramientas

§01 GUÍA DEL TEMA

La capa de tareas rutinarias de la seguridad web

La mayor parte del trabajo de seguridad de una semana normal de ingeniería no es adversarial. Es mecánico: elegir un algoritmo de resumen, generar una credencial que satisfaga la política de alguien, leer las reclamaciones de un token para ver por qué falló la autenticación, escribir una Content-Security-Policy que no rompa el sitio, limpiar una captura antes de pegarla en un ticket. Nada de eso se parece a un test de intrusión, y ahí es donde empiezan los incidentes de verdad: el modo de fallo es una mala costumbre, no una habilidad que falte.

El modelo que previene la mayoría de esas costumbres es una división en tres que la gente colapsa en una sola. La codificación — Base64, codificación en porcentaje, Punycode — es reversible y no implica ningún secreto; cambia la forma de los datos, nunca su confidencialidad. El hashSHA-256, SHA-512 — es de un solo sentido y tampoco implica secreto alguno; demuestra que dos secuencias de bytes son idénticas, nada más. Las operaciones con clave — HMAC, firmas JWT, TLS — son las únicas que demuestran quién produjo algo, y solo mientras la clave siga siendo secreta. Sin clave no hay autenticación: un bloque en Base64, un resumen desnudo y una carga útil de JWT descodificada son afirmaciones legibles sin nada detrás.

El segundo eje es la dirección. Las tareas que emiten política — directivas de CSP, encabezados, secretos generados — solo son correctas una vez que verificas el artefacto en la respuesta desplegada. Las tareas que inspeccionan algo que te han entregado llevan el riesgo opuesto: lo que hay dentro del artefacto. La censura pertenece a este grupo porque la forma habitual en la que los secretos salen de una empresa es un HAR adjunto a un informe de error, no un exploit.

Qué garantiza realmente cada primitiva

PrimitivaDemuestraNo aportaUso indebido habitual
Base64 / codificación de URLEl transporte seguro de bytes por canales de textoConfidencialidad: cualquiera puede revertirlo«Esconder» una clave de API en una carga útil
SHA-256 / SHA-512Integridad: misma entrada, mismo resumenSecreto; coste de fuerza bruta con entradas de baja entropíaGuardar hashes de contraseñas
SHA-1Compatibilidad con sumas de comprobación heredadasResistencia a colisiones (prácticamente roto)Firmas; deduplicación de entradas hostiles
HMAC (hash + clave secreta)Autenticidad mientras la clave siga siendo secretaConfidencialidad: la carga útil sigue legibleEnviar la clave a un navegador
Argon2id / bcrypt / scryptAlmacenamiento de contraseñas con sal y deliberadamente lentoVelocidad: la lentitud es la funciónCambiarlo por un hash rápido «por rendimiento»
Firma JWT (HS256, RS256)Autenticidad del emisor — solo después de verificarNada en absoluto, si solo descodificasConfiar en las reclamaciones de una carga útil descodificada
Content-Security-PolicyUna lista de permitidos que aplica el navegador a las cargasUn arreglo de la inyección; los clientes que no son navegadoresDejar 'unsafe-inline' en script-src
TLS + Strict-Transport-SecurityConfidencialidad del transporte; sin retroceso a httpCualquier afirmación sobre la lógica de la aplicaciónLeer un candado como «la aplicación es segura»

Cuánta entropía es suficiente

La entropía es longitud × log2(tamaño del conjunto), así que el conjunto importa tanto como la longitud.

Conjunto de caracteresBits por carácter8 car.14 car.20 car.
a–z (26)4,70386694
a–z0–9 (36)5,174172103
a–zA–Z0–9 (62)5,954883119
los cuatro juegos (87)6,445290129

Por debajo de 40 bits está roto; 80 es el suelo para una cuenta que importa; un UUID v4 aleatorio lleva 122 bits.

Elegir la herramienta adecuada

Para huellas, el Generador de Hash calcula SHA-1, SHA-256, SHA-384 y SHA-512 a la vez mediante Web Crypto, de modo que un resumen coincide con echo -n "text" | shasum -a 256 byte a byte: la forma rápida de conciliar una suma de comprobación cuyo algoritmo nadie anotó. MD5 no está porque Web Crypto no lo implementa.

Para los secretos que creas, la pregunta es quién guarda el valor. El Generador de Contraseñas encaja cuando lo guarda una persona o un gestor de contraseñas y un sitio impone una política de longitud o de conjunto de caracteres; informa de la entropía en vivo para el conjunto que hayas activado. El Generador UUID encaja cuando quien lo consume es una máquina y quieres un identificador opaco sin negociar juegos de caracteres. Los dos se apoyan en un CSPRNG — el generador de contraseñas toma de crypto.getRandomValues y el de UUID de crypto.randomUUID() — así que ninguno recurre a Math.random.

Para los tokens, el Decodificador JWT divide header.payload.signature, presenta con formato las dos primeras partes y muestra iat, exp y nbf como ISO 8601 con un veredicto de caducidad: lo suficiente para zanjar «¿está caducado o las reclamaciones están mal?» en un solo pegado. Usa Base64 cuando todo lo que has salvado de un registro es un único segmento; el Base64url usa - y _, así que cámbialos primero por + y /.

Para la política, mantén separadas la redacción y la verificación. El Generador CSP ensambla el encabezado desde 14 campos por directiva sobre una base endurecida — default-src 'self', object-src 'none', base-uri 'self', frame-ancestors 'none' — y el hub de CSP va directiva por directiva. Después demuestra que la respuesta desplegada lo lleva con Cabeceras HTTP, que solicita desde el servidor y muestra los encabezados en bruto tal como los envió el origen. Los CDN reescriben encabezados, y una etiqueta <meta> no puede llevar frame-ancestors.

Antes de compartir, el Visor HAR lee tu propia captura — método, estado, tipo MIME, tamaño, tiempos por entrada — mientras el Sanitizador HAR prepara la copia que saldrá de tu equipo, sustituyendo los encabezados cookie, authorization, x-api-key y similares por [REDACTED], vaciando los cuerpos y enmascarando los parámetros de consulta con aspecto de token. Cuando el sospechoso es una sola URL, el Parseador de URL descodifica la cadena de consulta para mostrar si hay un token firmado dentro, y el Convertidor IDN revela si un dominio que imita a otro es en realidad cirílico en su forma xn--.

Todo esto se ejecuta localmente salvo el verificador de encabezados, que envía tu URL a api.sitekits.dev. /es/for/security/ reúne la mayoría de estas herramientas en una página; las más generalistas (UUID, Base64, el visor de HAR) están en otros conjuntos por rol, y el hub de privacidad cubre lo que filtra tu navegador.

Trampas que provocan incidentes reales

Un token descodificado no es un token verificado

Descodificar solo demuestra que el Base64url está bien formado. La verificación necesita la clave del emisor, un algoritmo fijado y comprobaciones de exp / nbf / iss / aud en el servidor. Nunca tomes el algoritmo del propio encabezado alg del token: así funcionan alg: none y la confusión de RS256 a HS256.

Un hash rápido no es almacenamiento de contraseñas

Un SHA-256 desnudo de una contraseña es un banco de pruebas para GPU, no una defensa; sin sal, una sola tabla arcoíris rompe a todos los usuarios. Hacer hash para comparar archivos es el caso opuesto: ahí un resumen rápido es lo correcto.

'unsafe-inline' cancela la mayor parte de la CSP

Vuelve a permitir exactamente el script en línea inyectado que la CSP existe para bloquear. Usa nonces o hashes. Un connect-src con comodín es la misma trampa por el otro lado: la exfiltración sigue abierta aunque la ejecución de scripts esté cerrada.

La censura es coincidencia de patrones, no comprensión

El saneador compara con una lista fija de encabezados y con nombres de parámetro que contengan token, key, secret, password, passwd, pwd, auth, session, sig o signature. Una credencial en un segmento de ruta de una URL, o llamada t, sobrevive; y un recuento de censuras igual a cero en una sesión autenticada es una señal, no un aprobado.

La entropía describe el generador, no la cadena

La fórmula solo se cumple cuando cada carácter se tomó al azar. P@ssw0rd!2024 tiene 13 caracteres y las cuatro clases, y sin embargo está en todas las listas de descifrado. Solo la forma en que se generó una cadena decide si la puntuación de un medidor significa algo.

FAQ
¿Es SHA-256 suficiente para guardar contraseñas?
No. SHA-256 es rápido por diseño, y las GPU de consumo calculan miles de millones de resúmenes por segundo, así que un atacante con una tabla de hashes filtrada rompe las contraseñas cortas o comunes en horas. Usa una KDF con sal y deliberadamente lenta — Argon2id, bcrypt o scrypt — con un factor de trabajo ajustado. SHA-256 es la elección correcta para integridad de archivos, direccionamiento por contenido y detección de cambios, no para credenciales.
¿Puedo confiar en un JWT una vez descodificado?
No. El encabezado y la carga útil de un JWT van codificados en Base64url, no cifrados ni protegidos, así que cualquiera puede leerlos y cualquiera puede fabricar un token con reclamaciones arbitrarias. Solo verificar la firma contra la clave del emisor demuestra quién lo emitió. Descodificar sirve para depurar: aplica exp, nbf y la audiencia en el servidor, porque el reloj de un cliente puede estar mal o mentir a propósito.
¿Cuántos caracteres necesita realmente una contraseña?
Depende del conjunto de caracteres, porque la entropía es longitud × log2(tamaño del conjunto). Con mayúsculas, minúsculas, dígitos y símbolos — un conjunto de 87 caracteres — cada carácter vale unos 6,44 bits, así que 13 caracteres son aproximadamente 84 bits y 20 caracteres unos 129. Solo minúsculas da 4,70 bits por carácter, así que 8 caracteres en minúsculas son unos 38 bits y se rompen por fuerza bruta. Apunta a 80 bits o más en las cuentas que importan.
¿Una Content-Security-Policy detiene el XSS?
Lo contiene, no lo arregla. Una política estricta impide que un script inyectado se ejecute o exfiltre datos, pero solo en los navegadores que aplican CSP, y solo si script-src evita 'unsafe-inline' y 'unsafe-eval'. Arregla la inyección con una codificación de salida correcta y usa la CSP para limitar el daño del error que se te pasó. Despliega primero con Content-Security-Policy-Report-Only y confirma después que el encabezado en vigor está presente en la respuesta real.
¿Puedo esconder una clave de API codificándola en Base64 dentro de una carga útil?
No. Base64 es una codificación, no un cifrado: no usa ninguna clave, y cualquiera que tenga la carga útil recupera los bytes originales con una sola orden, razón por la cual un descodificador no necesita nada de ti para leerla. El problema de fondo es la ubicación más que el formato: cualquier secreto que se envíe a un navegador o a un binario móvil ya está divulgado, envuelto en lo que sea. Guarda la clave de larga duración en el servidor y dale al cliente algo que demuestre autenticidad sin ser el secreto: un token de corta duración, o una petición firmada con HMAC cuya clave nunca sale de tu infraestructura.