Guía
Una lista de seguridad para trabajar antes de lanzar
11 minutos de lectura · Publicado
Veintidós preguntas, agrupadas en seis áreas. Cada una tiene un sí o un no, y cada una dice qué pasa si la respuesta es no — porque el sentido de una lista es dejarte decidir con qué estás dispuesto a lanzar, no hacerte sentir atrasado.
Nada de esto es específico de un framework, y no hace falta un fondo de seguridad. Si puedes leer tu propio código y cargar tu propio sitio, puedes responder las veintidós. Trabaja de arriba abajo: el orden es aproximadamente por lo que cuesta una respuesta incorrecta.
Secretos y credenciales
- ¿Cada clave de API y URL de base de datos se lee del entorno? Busca en el código los prefijos que usan tus proveedores —
sk_,AKIA,ghp_,-----BEGIN. Si una clave está en el código, cualquiera con acceso al repositorio la tiene, que suele incluir a más gente de la que crees. - ¿Se ha revisado el historial de git, no solo el árbol de trabajo?
git log --all -p -S "sk_live". Borrar un secreto en un commit posterior no lo quita del repositorio, y reescribir el historial no lo des-divulga. Si encuentras uno, rótalo antes de hacer cualquier otra cosa. - ¿Las credenciales de producción son distintas de las de tu portátil? Compartirlas significa que un error en desarrollo es un error en producción, y que no puedes revocar un portátil sin tumbar el sitio.
- ¿Sabes cómo rotar cada una? No en teoría. Qué página, qué botón y qué se rompe en los minutos entre que muere la clave vieja y se despliega la nueva. La primera vez que hagas esto no debería ser durante un incidente.
Autenticación
- ¿Las cookies de sesión son
HttpOnly,Securey están acotadas conSameSite? Carga tu sitio y lee las cabeceras de respuesta. SinHttpOnly, cualquier script de la página puede leer la sesión; sinSecure, viaja por HTTP plano si algo degrada la conexión. - ¿Un restablecimiento de contraseña invalida las sesiones existentes? Quien restablece una contraseña suele creer que accedieron a su cuenta. Si la sesión del atacante sobrevive, el restablecimiento no hizo nada.
- ¿Hay un límite de tasa en el acceso, el alta y el restablecimiento? Sin uno, un atacante puede probar una lista de contraseñas filtradas contra tus usuarios tan rápido como responda tu servidor, y tu endpoint de restablecimiento se convierte en una forma de enviar correo desde tu dominio.
- ¿Los accesos fallidos dicen lo mismo exista o no la cuenta? «No hay cuenta con ese correo» convierte tu formulario de acceso en una forma de comprobar cuáles de un millón de direcciones son tus clientes.
Autorización
- ¿Cada endpoint que lee un registro por id comprueba quién pregunta? Es el fallo serio más habitual en una aplicación construida rápido. Recorre cada ruta que toma un id de la petición y pregunta qué impide que alguien envíe otro. «La interfaz solo les muestra los suyos» no es una respuesta; la interfaz no es un control.
- ¿La comprobación de pertenencia está en la consulta y no después? Una búsqueda acotada a
{ id, ownerId: session.userId }no puede devolver la fila de otra persona. Una búsqueda seguida de unifse puede copiar sin su segunda mitad. - ¿Los endpoints de escritura comprueban lo mismo que los de lectura? Actualizar y borrar se olvidan a menudo porque primero se corrigió la lectura y pareció la parte difícil.
- ¿Las rutas de administración están protegidas por una comprobación en el servidor? Ocultar el enlace, o comprobar un rol en el navegador, deja la ruta abierta a quien teclee la URL.
- ¿Un usuario puede cambiar campos que no debería enviando propiedades extra? Si pasas el cuerpo de la petición a una llamada de actualización, una petición con
roleoplanpuede establecerlos. Valida contra una lista explícita de campos en lugar de filtrar los que se te ocurrieron.
Pagos
- ¿El manejador del webhook verifica la firma antes de leer el cuerpo? Y rechaza si falla, en lugar de registrar y continuar. Un manejador sin verificar deja que cualquiera que conozca la URL te diga que una factura se pagó.
- ¿Los importes cobrados salen de tu propia base de datos? Si el navegador envía un importe y el servidor lo cobra, tus precios se editan en las herramientas de desarrollador. Envía un identificador de producto; busca el precio.
- ¿Un evento de webhook repetido es inofensivo? Los proveedores reintentan. Un manejador que añade un mes de acceso cada vez que corre acabará regalando varios. Registra el id del evento e ignora uno que ya hayas procesado.
- ¿El acceso se deriva del estado de la suscripción y no de un evento pasado? Si una cancelación o un pago fallido no te llega, los derechos deberían caducar solos en lugar de persistir porque nadie les dijo que pararan.
Dependencias y datos
- ¿Has ejecutado la auditoría de tu gestor de paquetes y leído la salida? Léela, no la cuentes: una dependencia solo de build con un aviso grave suele ser menos urgente que una que atiende peticiones con uno medio.
- ¿Hay una decisión registrada para lo que no estás corrigiendo? Un riesgo aceptado con fecha es una decisión. Un riesgo aceptado sin ella es algo que olvidaste.
- ¿Hay copias de seguridad de la base de datos, y has restaurado una? Una copia que nunca has restaurado es una creencia sobre una copia. Restaura una vez en una base de pruebas, antes de necesitarlo.
- ¿Tus logs se mantienen libres de contraseñas, tokens y datos de tarjeta? Registrar el cuerpo entero de una petición es la forma habitual de que lleguen. Revisa sobre todo lo que registras en la ruta de error, que es donde la gente vuelca todo lo que tiene.
Configuración de despliegue
- ¿Producción está configurada de verdad como producción — sin salida de depuración, sin CORS permisivo, sin stack traces, sin rutas solo de desarrollo? Carga el sitio desplegado sin sesión y prueba una ruta que creas interna. Busca en la configuración
"*"en cualquier cosa de CORS, y cada comparación contraNODE_ENVque apague una comprobación.
Qué hacer con los noes
Escríbelos con la consecuencia al lado de cada uno, y decide. Algunos merecen retrasar un lanzamiento y otros no, y la diferencia es si el daño se deshace con una disculpa. Una clave de pago divulgada, un cliente leyendo los datos de otro y una base de datos que no puedes restaurar son los tres que no.
Todo lo demás es una lista que recorres en las primeras semanas, y una lista es una posición mucho mejor que la sensación vaga de que probablemente deberías haber comprobado algo.
Hacer esto otra vez el mes que viene
Lo difícil no es el primer pase. Es la cuarta funcionalidad, cuando la lista está en un documento que nadie ha abierto y las respuestas de la primera semana ya no son ciertas.
Esa repetición es para lo que sirve de verdad la automatización. Audixa ejecuta las comprobaciones de las secciones de secretos, dependencias, control de acceso y configuración contra tu repositorio, y — cuando hayas demostrado que controlas el dominio — contra lo que sirve tu sitio. Cada resultado trae el código o la cabecera que coincidió, para que puedas decir si es real. Ver la lista completa de lo que comprueba, o leer la guía compañera sobre por qué se repiten estos errores.
Lo que ninguna herramienta puede responder por ti es la pregunta nueve. Si un usuario dado debería poder ver un registro dado es un hecho sobre tu producto, no sobre tu código, y es la pregunta en la que merece la pena gastar tu propia hora.
Que las comprobaciones repetibles se ejecuten por ti
Conecta un repositorio o un servidor, ejecuta un análisis y lee los hallazgos, cada uno con su evidencia y los pasos para corregirlo.