Mejores prácticas para proteger una API REST/servicio web [cerrado]
Al diseñar una API o servicio REST, ¿existen mejores prácticas establecidas para abordar la seguridad (autenticación, autorización, gestión de identidad)?
Al crear una API SOAP, tiene WS-Security como guía y existe mucha literatura sobre el tema. He encontrado menos información sobre cómo proteger los puntos finales REST.
Si bien entiendo que REST intencionalmente no tiene especificaciones análogas a WS-*, espero que hayan surgido mejores prácticas o patrones recomendados.
Cualquier discusión o enlace a documentos relevantes será muy apreciado. Si es importante, usaríamos WCF con mensajes serializados POX/JSON para nuestros servicios/API REST creados con la versión 3.5 de .NET Framework.
Como dijo tweakt, Amazon S3 es un buen modelo con el que trabajar. Sus firmas de solicitudes tienen algunas características (como la incorporación de una marca de tiempo) que ayudan a proteger contra la repetición de solicitudes tanto accidentales como maliciosas.
Lo bueno de HTTP Basic es que prácticamente todas las bibliotecas HTTP lo admiten. Por supuesto, necesitarás SSL en este caso porque enviar contraseñas en texto plano a través de la red es casi universalmente algo malo. Es preferible Basic a Digest cuando se usa SSL porque incluso si la persona que llama ya sabe que se requieren credenciales, Digest requiere un viaje de ida y vuelta adicional para intercambiar el valor nonce. Con Basic, quien llama simplemente envía las credenciales la primera vez.
Una vez que se establece la identidad del cliente, la autorización es en realidad solo un problema de implementación. Sin embargo, podría delegar la autorización a algún otro componente con un modelo de autorización existente. Nuevamente, lo bueno de Basic aquí es que su servidor termina con una copia en texto plano de la contraseña del cliente que puede simplemente pasar a otro componente dentro de su infraestructura según sea necesario.
No existen estándares para REST distintos de HTTP. Existen servicios REST establecidos. Le sugiero que les eche un vistazo y tenga una idea de cómo funcionan.
Por ejemplo, tomamos prestadas muchas ideas del servicio S3 REST de Amazon cuando desarrollamos el nuestro. Pero optamos por no utilizar el modelo de seguridad más avanzado basado en firmas de solicitud. El enfoque más sencillo es la autenticación básica HTTP sobre SSL. Tienes que decidir qué funciona mejor en tu situación.
Además, recomiendo encarecidamente el libro RESTful Web Services de O'reilly. Explica los conceptos básicos y proporciona algunas de las mejores prácticas. Generalmente puede tomar el modelo que proporcionan y asignarlo a su propia aplicación.
Hay una excelente lista de verificación en Github :
Autenticación
No reinvente la rueda en autenticación, generación de tokens y almacenamiento de contraseñas. Utilice los estándares.
Utilice
Max Retry
y encarcele funciones en Iniciar sesión.Utilice cifrado en todos los datos confidenciales.
JWT (token web JSON)
Utilice una clave aleatoria complicada (JWT Secret) para hacer que la fuerza bruta del token sea muy difícil.
No extraiga el algoritmo de la carga útil. Fuerce el algoritmo en el backend (HS256 o RS256).
Haga que la caducidad del token (
TTL
,RTTL
) sea lo más corta posible.No almacene datos confidenciales en la
JWT
carga útil, se pueden decodificar fácilmente.
OAuth
Valide siempre
redirect_uri
el lado del servidor para permitir solo las URL incluidas en la lista blanca.Intente siempre intercambiar por código y no por tokens (no lo permita
response_type=token
).Utilice el parámetro de estado con un hash aleatorio para evitar
CSRF
elOAuth
proceso de autenticación.Defina el alcance predeterminado y valide los parámetros del alcance para cada aplicación.
Acceso
Limite las solicitudes (regulación) para evitar ataques DDoS/fuerza bruta.
Utilice HTTPS en el lado del servidor para evitar MITM (Man In The Middle Attack)
Utilice
HSTS
el encabezado con SSL para evitar el ataque SSL Strip.
Aporte
Utilice el método HTTP adecuado según la operación:
GET
(leer),POST
(crear),PUT/PATCH
(reemplazar/actualizar) yDELETE
(para eliminar un registro), y responda405 Method Not Allowed
si el método solicitado no es apropiado para el recurso solicitado.Valide el tipo de contenido en
Accept
el encabezado de la solicitud (Negociación de contenido) para permitir solo el formato compatible (p. ejapplication/xml
.application/json
, etc.) y responda con406 Not Acceptable
una respuesta si no coincide.Valide
content-type
los datos publicados cuando los acepte (por ejemploapplication/x-www-form-urlencoded
,multipart/form-data
,application/json
, etc.).Valide la entrada del usuario para evitar vulnerabilidades comunes (por ejemplo, XSS, inyección SQL, ejecución remota de código, etc.).
No utilice datos confidenciales (credenciales, contraseñas, tokens de seguridad o claves API) en la URL, pero utilice el
Authorization
encabezado estándar.Utilice un servicio API Gateway para habilitar el almacenamiento en caché,
Rate Limit
las políticas (por ejemplo, cuota, detención de picos, límite de tasa concurrente) e implementar recursos API dinámicamente.
Procesando
Compruebe si todos los puntos finales están protegidos mediante autenticación para evitar un proceso de autenticación interrumpido.
Se debe evitar la identificación del recurso propio del usuario. Utilice /me/orders en lugar de /user/654321/orders.
No incremente automáticamente los ID. Utilice UUID en su lugar.
Si está analizando archivos XML, asegúrese de que el análisis de entidades no esté habilitado para evitar XXE (ataque de entidad externa XML).
Si está analizando archivos XML, asegúrese de que la expansión de entidades no esté habilitada para evitar la bomba Billion Laughs/XML mediante un ataque de expansión de entidades exponencial.
Utilice una CDN para cargar archivos.
Si está tratando con una gran cantidad de datos, utilice Trabajadores y Colas para procesar la mayor cantidad posible en segundo plano y devolver una respuesta rápidamente para evitar el bloqueo HTTP.
No olvide desactivar el modo DEBUG .
Producción
Enviar
X-Content-Type-Options: nosniff
encabezado.Enviar
X-Frame-Options: deny
encabezado.Enviar
Content-Security-Policy: default-src 'none'
encabezado.Elimine los encabezados de huellas digitales:
X-Powered-By
,Server
,X-AspNet-Version
etc.Fuerza
content-type
tu respuesta, si regresasapplication/json
entonces el tipo de contenido de tu respuesta esapplication/json
.No devuelva datos confidenciales como credenciales, contraseñas o tokens de seguridad.
Devuelve el código de estado adecuado según la operación completada. (por ejemplo
200 OK
,400 Bad Request
,401 Unauthorized
,405 Method Not Allowed
, etc.).
Quizás también quieras echar un vistazo a OAuth , un protocolo abierto emergente para autorización basada en tokens dirigido específicamente a API http.
Es muy similar al enfoque adoptado por Flickr y recuerda las apis de "descanso" de la leche (no necesariamente buenos ejemplos de apis descansadas, pero sí buenos ejemplos del enfoque basado en tokens).
Me sorprende un poco que aún no se haya mencionado SSL con certificados de cliente. Por supuesto, este enfoque sólo es realmente útil si se puede contar con que la comunidad de usuarios esté identificada mediante certificados. Pero varios gobiernos/empresas sí los emiten para sus usuarios. El usuario no tiene que preocuparse por crear otra combinación de nombre de usuario y contraseña, y la identidad se establece en todas y cada una de las conexiones, por lo que la comunicación con el servidor puede ser completamente sin estado y no se requieren sesiones de usuario. (No implica que alguna o todas las otras soluciones mencionadas requieran sesiones)