Seguridad en tus APIs: cómo evitar ataques de securización

En un post anterior identificamos las diferentes vulnerabilidades a nivel de API y los principios básicos que se deben tener presentes a la hora de su implementación.

En este artículo se darán algunas recomendaciones para mitigar los diferentes vectores de ataque para cada tipología de vulnerabilidad.

Validación de los parámetros

Para el caso de vulnerabilidades referente a los parámetros se recomienda establecer las siguientes medidas:

El primer paso para cualquier implementación de API es comprobar la validez de todos los datos entrantes verificando su formato, su validez y garantizar que no puede causar daño al sistema

La defensa más efectiva para los ataques de inyección consiste en validar los datos entrantes contra un esquema estricto utilizando formatos específicos de datos incluso rangos y/o conjuntos de posibles valores, sin olvidarnos de limitar el tamaño en caso de campos de texto libres.

Hay que tener en cuenta que la mayoría de los esquemas generados de manera automática con las herramientas de desarrollo producen esquemas demasiado amplios, lo que implica dedicar especial atención a los posibles errores de validación. 

Una posible lista de consejos para realizar esta validación sería la siguiente:

  • Validar los tipos de contenido en la solicitud (Content-type):

Cuando se crean/actualizan datos en el servidor se envía información desde el cliente de la API en cuyo caso el servidor nunca debe asumir el tipo de contenido por defecto. 

Siempre debe solicitar la cabecera Content-Type por parte del cliente y validar primero que admite ese tipo de contenido, por ejemplo application/json y segundo que el cuerpo de la petición contiene la información en dicho formato. 

En caso de que el cliente no envie la cabecera el servidor debe contestar con un código HTTP 406 No Aceptable, y en caso de que indique uno que no sea válido por parte del servidor, devolver un 415 Unsupported Media Type.

  • Validar los tipos de contenido en la salida (Accept):

Es habitual que los servicios Rest admitan múltiples tipos de respuesta, por ejemplo: application/json y application/xml y el cliente especifique el orden del formato en el que prefiere recibir los datos haciendo uso de la negociación de contenido con la cabecera Accept. 

No se debe admitir esta cabecera vacía o sin un valor específico, debe ser obligatorio en las peticiones desde el cliente indicar el formato que prefiere en la respuesta. 

En caso de que el cliente no envie la cabecera Accept el servidor debe contestar con un código HTTP 406 No Aceptable y en caso de que indique uno que no sea válido un 415 Unsupported Media Type. 

Debido a que hay muchos tipos MIME para los tipos de respuesta típicos, es importante documentar específicamente para los clientes los tipos MIME que se deben usar en cada API.

  • Validación de las URL:

Los atacantes pueden manipular cualquier parte de la solicitud HTTP incluida la URL para intentar evitar los mecanismos de seguridad del sitio. 

Ataques típicos a nivel de URL incluyen: navegación forzada, inserción de comandos, desbordamientos del búfer, manipulación de campos ocultos, ataques de cadenas de formato, etc.

  • Control cabeceras HTTP:
    • Si una API expone sólo el método GET sobre un recurso en caso de que el cliente solicite otros métodos el servidor debe devolver un 405 Method Not Allowed y no debe permitir una solicitud que contenga la cabeceras: X-HTTP-Method-Override o X-Method-Override ya que puede sobreescribir el método que se utiliza en la URL. 

Detalle de la vulnerabilidad: https://vulncat.fortify.com/en/detail?id=desc.dynamic.xtended_preview.often_misused_http_method_override

  • El servidor debe enviar la cabecera: X-Content-Type-Options con valor nosniff para asegurarse que el navegador no intente detectar Content-Type diferentes al que realmente se envia para evitar posibles ataques XSS.
  • El cliente debe enviar la cabecera X-Frame-Options: con el valor deny en caso contrario el servidor debe rechazar la solicitud. El valor deny es para evitar posibles ataques de arrastrar y soltar clickjacking en navegadores.
  • Codificación XML y codificación:

Los servicios basados ​​en XML deben garantizar que están protegidos contra ataques comunes basados ​​en XML mediante el uso de análisis XML seguro. Normalmente, esto significa proteger contra ataques de entidad externa XML, ajuste de firma XML, etc. 

También es recomendable utilizar siempre serialializadores para evitar ataques de inyección XML. garantizando que el contenido proporcionado por el cliente sea una XML válido.

  • Codificación JSON:

Una de las principales preocupaciones de las codificaciones JSON es evitar la ejecución arbitraria de código remoto Javascript en el navegador o en el servidor. 

Para evitarlo resulta vital usar un serializador JSON para codificar correctamente los datos enviados por el cliente y evitar la ejecución de código incluido dentro de la información introducida por el cliente.

  • Datos sensibles en la URL:

Como se ha explicado antes, toda la información que va en la url es susceptible de ser almacenada y hay que evitar como sea incorporar información sensible en la misma: como números de cuenta, datos de la tarjeta, teléfono, email o incluso datos de salud personal así como datos asociados a la autenticación y autorización DOM tokens o password. 

El envío de claves como parte de la URL puede hacer que la clave se vea comprometida. Como se explica en IETF RFC 6819, dado que los detalles de URI pueden aparecer en los registros del sistema o del navegador, otro usuario podría ver los URI desde el historial del navegador, lo que hace que las claves de API, las contraseñas y las fechas confidenciales en los URI de API sean fácilmente accesibles.

Para evitarlo algunas recomendaciones son:

  • Modificar el diseño de la API para que dicha información en lugar de ir en la URL vaya en el cuerpo de la petición mediante un POST. 
  • Evitar que esa información viaje por la red a menos que sea imprescindible.
  • Incorporar mecanismos de cifrado de datos confidenciales y delicados como algo prioritario. Además de usar TLS, es importante que el tráfico de API esté protegido mediante el cifrado de datos confidenciales, la implementación del enmascaramiento de datos para el rastreo/registro y el uso de tokenización para dicha información.
  • Mensajes de error demasiado explícitos:

En el momento en el que se produce un error al invocar una API se aconseja devolver por parte del servidor un error que sea suficientemente explicativo para que el cliente pero no enviar el stack trace del error del backend. 

Si se propaga el error devuelto por el backend, incluyendo el stack trace, potencialmente puede convertirse en una fuga de información para el usuario malintencionado revelando la implementación de la arquitectura subyacente con nombres de clases, paquetes, versiones, servidores e incluso consultas SQL. 

Los atacantes pueden explotar esta información enviando peticiones a la API con malas intenciones. Para evitarlo se recomienda devolver un objeto de error con información de manera equilibrada, es decir, que incluya suficiente información como para que el cliente identifique el error pero sin desvelar detalles técnicos del error producido. 

Lo que se recomienda es enviar el código HTTP asociado con un alias y mensaje de error que sea suficientemente explicativo y sin incorporar el stack trace del backend. 

Los API gateway se pueden utilizar para transformar los mensajes de error de los backend en mensajes estandarizados para que todos los errores sean similares y eliminar la exposición de la información y de la estructura de error del backend.

Autenticación y autorización

Para el caso de vulnerabilidades asociadas a los flujos de autorización y autenticación se recomienda:

  • Proteger los métodos HTTP:

No todos los métodos HTTP realizan la misma funcionalidad ni todas los clientes de la API deben tener permiso y acceso a dichos métodos. 

Es habitual que sobre un mismo recurso se exponen métodos de consulta como el GET y métodos con un rol operativo como POST, PUT, y DELETE siendo estas últimas operaciones susceptibles de un control de acceso más estricto, ya que solo personas con permisos especiales como un gestor o los propios dueños de los datos las puedan realizar. 

Para asegurar que las personas correctas acceden a los métodos a los que están autorizados debe implementarse algún método de autorización como Oauth o OpenId Connect, así como hacer uso de los scopes para implementar esa granularidad de acciones sobre un recurso. 

En resumen, es importante que el servicio restrinja correctamente los verbos permitidos, de modo que solo funcionen los métodos autorizados para las personas adecuadas y, en caso contrario, devolver un código HTTP 403 Forbidden.

Transporte

Para el caso de vulnerabilidades asociadas a ataques a nivel de transporte:

  • Proteger contra ataques CSRF (cross-site request forgery)

Es importante asegurar sobre todo sobre los verbos PUT, PATCH, POST y DELETE estén protegidos contra ataques CSRF normalmente haciendo uso de un enfoque basado en token como el estándar OAuth.

Aún así es posible generar tokens aleatorios si hay errores XSS dentro de la aplicación, luego también hay que asegurarse por parte del servicio su prevención de ataques XSS. 

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

También se debe considerar el uso de certificados del lado del cliente con autenticación mutua para proporcionar protección adicional sobre todo para servicios cuya operativa implique un mayor control y/o privilegios del cliente.

  • Aplicar mecanismos de criptografía en diferentes niveles:
    • Datos en tránsito: el uso de TLS debe ser obligatorio SIEMPRE, especialmente en operaciones en las que se involucra información sensible, credenciales y con operaciones de actualización y eliminación de información. 

El inconveniente del aumento de latencia por el uso de TLS es ínfimo en sistemas actuales frente a la seguridad que aporta al usuario final y a la información expuesta.

  • Datos almacenados: cualquier aplicación en mayor o menor medida maneja datos confidenciales y los almacena, para evitar posibles acceso no autorizados a esa información algunas recomendaciones son:
    • Cifrar todos esos datos antes de almacenarlos.
    • Asegurarse que todas las copias de seguridad externas o internas están cifradas y que la administración y respaldo de claves se gestione de manera independiente.
    • Utilizar algoritmos estandarizados fuertes para la administración de claves.
    • Asegurarse que todas las contraseñas almacenadas estén cifradas con un algoritmo sólido y estanda y protegidas contra accesos no autorizados. Puedes ver más detalle aquí.
  • Integridad del mensaje: además de usar HTTPS/TLS, se recomienda el uso de JSON WEB TOKEN (JWT). Se trata de un estándar (RFC 7519) que define de una forma compacta y autónoma el método para la transmisión de información entre dos partes en un objeto JSON. 

Este objeto JSON incluye el valor del hash de la firma digital del cuerpo del mensaje que se envía lo cual permite garantizar la integridad del mensaje durante su transmisión. 

Además JWT no solo sirve para garantizar la integridad del mensaje, sino también la autenticación del remitente/receptor del mensaje. Aquí tienes más información al respecto.

  • Uso inesperado de la API: siempre es complicado estimar el uso de una API ya que un aumento inesperado del número de peticiones puede afectar directamente al backend tirando la aplicación. 

Una buena práctica es imponer una cuota de uso por aplicación para evitar que el backend se vea afectado por un tráfico elevado. Estas limitaciones y control de cuotas suelen implementarse mediante plataformas de gestión de APIs. 

Otra de las ventajas de hacer uso de este control de tráfico y el uso de cuotas es minimizar el impacto de ataques por repetición

Las APIs que se encuentran expuestas al público se enfrentan al desafío de confiar en las peticiones entrantes, incluso en caso de peticiones en las que se niega el acceso por confianza hay APIs que permiten «cortésmente» que el usuario lo intente de nuevo, lo cual puede inducir a reproducir solicitudes de fuerza bruta y de denegación de servicio. 

Las medidas en este caso residen en limitar la velocidad entre peticiones o incluso el uso de herramientas de análisis del tráfico para identificar patrones de peticiones de un bot por ejemplo. 

También suele ayudar el uso de HMAC con marcas de tiempo para limitar la validez de la transacción un periodo de corto de tiempo, realizar autenticación de dos factores y habilitar tokens de acceso de corta duración con OAuth.

Checklist

Con el objetivo de ayudarnos a que las recomendaciones anteriores se sigan dentro de un proyecto se ha elaborado la siguiente checklist con las medidas de seguridad asociadas a cada categoría de vulnerabilidad y al tipo de riesgo según OWASP para ayudar a mitigarlo.

Conclusiones

Todas las organizaciones con una estrategia de apificación deben abordar la seguridad como un desafío arquitectónico mucho antes que tenga lugar al desarrollo y como muy tarde a la vez que se realiza la implementación para evitar problemas posteriores. 

Un error de seguridad de la API puede tener consecuencias significativas, pero con la previsión y la administración adecuadas la mayoría de problemas se seguridad se minimizan notablemente.

En este post hemos visto cómo la mayoría de amenazas potenciales se pueden evitar:

  • Pensando en el diseño de la API para evitar exponer información sensible o innecesaria.
  • Estableciendo políticas para:
    • La verificación de contrato evitando la inyección y manteniendo la integridad del mensaje.
    • La gobernabilidad y control de acceso autorizando el acceso solo a quien corresponda.
    • La monitorización de los errores y con la gestión de alertas que nos avisen de problemas.
    • El establecimiento de límites de consumo mediante cuotas.

Resulta fundamental promover la capacitación a nivel de seguridad de los desarrolladores desde la propia organización como base en el desarrollo software. 

Dentro de este programa formativo o de capacitación, debe enfatizarse también la securización de las APIs para trasladar las implicaciones que tiene la exposición de información a través de ellas y  que desde el principio se planteen sus posibles consecuencias para mitigar los problemas antes de que se conviertan en una realidad.

Referencias

Foto de noeliamartin

Ingeniero Superior en Telecomunicaciones. Inicié mi carrera programando servicios hasta llegar al mundo de las APIs. Actualmente trabajo en Paradigma en el departamento de Arquitectura dentro del área de API Management y gobierno intentando promover las buenas prácticas en diseño y desarrollo de las APIs.

Ver toda la actividad de Noelia Martín

Escribe un comentario