Desarrollar una API REST implica dedicar un esfuerzo importante de recursos y personas. Pero ¿cómo exponer mi API de forma segura?. Si queremos comercializar nuestra API, el aspecto de la seguridad adquiere especial importancia, y si nos movemos en el sector de la Salud, este asunto es absolutamente clave.
Implementar una buena capa de securización de nuestra API nos evitará muchos problemas, aunque requerirá de nosotros un importante esfuerzo.
En este artículo expondremos los principales métodos de autenticación y autorización que podemos emplear para securizar una API REST, y comentaremos otros aspectos relativos a la seguridad que debemos tener presentes.
Finalmente veremos una buena alternativa para reducir drásticamente el esfuerzo necesario para comercializar nuestra API REST de forma segura.
Tabla de Contenidos
INTRODUCCIÓN
En primer lugar fijemos dos conceptos tan básicos como importantes: autenticación y autorización.
Los métodos de autenticación garantizan que el usuario que accede a nuestros recursos es quien dice ser.
Los métodos de autorización garantizan que el usuario autenticado que accede a un determinado recurso, tiene autorización para ese recurso.
Dicho esto, hay un aspecto particular del diseño de API REST (2) que afecta a la seguridad:
LAS PETICIONES DEBEN SER SIN ESTADO
Desde el punto de vista del desarrollador esto afecta a cómo implementar la confirmación de la identidad del usuario, es decir la autenticación, dado que en cada petición debemos garantizar que el cliente tiene permiso para acceder a nuestros recursos.
Cuando se desarrolla una aplicación web, este aspecto no es imprescindible. Habitualmente se obvia, ya que es un humano quien está interactuando con la aplicación desde un cliente web.
En estos casos se puede mantener la sesión con el navegador del usuario empleando una cookie, almacenando el identificador de la sesión en el lado del servidor.
Pero cuando tratamos con APIs REST esto no es lo deseable. En el lado del cliente, lo que hay es un software.
AUTENTICACIÓN DE ACCESO BÁSICO
La solución es no gestionar el estado en el servidor, devolviendo un token que el cliente enviará en cada nueva petición y que el servidor será capaz de interpretar.
Pero vayamos por partes. En el siguiente diagrama vemos la interacción entre una aplicación web (o nuestro navegador) y el backend donde se publica el endpoint de la API.
Figura 1: Client access to API
En el primer paso, la aplicación debe enviar las credenciales de acceso a la API mediante el empleo de una cabecera (header Authentication) y es aquí donde debemos empezar a tener cuidado.
Si la comunicación con el endpoint de la API no se hace mediante HTTPS alguien puede escuchar y leer el usuario y contraseña, aunque se emplee algún método de codificación (habitualmente un base64 de usuario:contraseña).
A este mecanismo se le denomina Autenticación de acceso básico (Basic access authentication) (3).
La Autenticación Básica no es muy segura por dos razones:
- en primer lugar la codificación basada en base64 es fácil de romper, y una vez obtenido cualquier cliente puede hacer uso de la API,
- y en segundo lugar no se comprueba el recurso al que se accede, por lo que una misma petición es válida para cualquier recurso. Tan solo hay que probar varios y determinar si se tiene acceso o no.
AUTENTICACIÓN DE ACCESO DIGEST
Por estos motivos surge la Autenticación de acceso Digest (Digest access authentication)”.
Consiste en que el servidor donde corre la API genera de forma aleatoria una serie de valores. Estos valores los envía mediante diferentes cabeceras, como respuesta a una primera petición que es respondida con un código 401.
El cliente genera un hash con el usuario, la contraseña, el recurso al que quiere acceder y los valores recibidos desde el servidor.
Este hash no puede ser alterado por un tercero ni decodificado, y tan solo cliente y servidor disponen de todos los elementos para generarlo y poder confiar mutuamente.
Como vemos esto se complica conforme vamos avanzando… pero, ¿qué pasa con las siguientes peticiones?
¿Debemos enviar de nuevo las credenciales o el hash con cada petición?
AUTENTICACIÓN BASADA EN COOKIES
La respuesta es no. Tan solo debemos almacenar un id de sesión en el servidor, e informar a la aplicación web que lo use en cada petición.
El mecanismo más conocido es usar cookies para informar del id de sesión (Autenticación basada en Cookies), pero esto implica almacenarlo tanto en el origen como en el destino y tener que gestionar el estado.
Para evitarlo podemos incluir ese id de sesión en un token junto con más información. Este token es inalterable y único.
AUTENTICACIÓN BASADA EN TOKENS
A este mecanismo se le conoce como Autenticación basada en Tokens (Token Bearer).
Existen muchos mecanismos para generar ese token, pero el más extendido y documentado es el basado en JSON Web Token (JWT) (4).
Se trata de una cadena formada por tres partes (cabecera, payload y firma), que son procesadas por un algoritmo de hash con una clave secreta.
Uff!!! , cuanto trabajo para asegurarnos que nadie descubre nuestra credenciales y que no nos puedan suplantar en cada invocación a la API. Por suerte existen multitud de librerías que facilitan al desarrollador este trabajo.
¿Y LA AUTORIZACIÓN?
Pero aquí no termina todo, ya que ahora debemos lidiar con la Autorización, es decir, que en base a las credenciales de acceso podamos determinar si el usuario puede consumir o no un recurso.
Naturalmente, todo depende de qué tipo de operaciones se pueden realizar con nuestra API.
Hay APIs que ofrecen información de solo lectura y poco o nada sensible, como una API de predicción climatológica.
En estos casos, puede interesarnos compartir ese recurso sin requerir ni autenticación ni autorización.
Otras veces, serán operaciones que afecten a datos sensibles o importantes para nuestro negocio, como en el caso de APIs para la Salud.
En estos casos se requiere autenticación y muy seguramente autorización, porque algunas operaciones serán de escritura y debemos controlar qué usuario puede realizarlas.
Veamos qué métodos podemos implementar para gestionar la autorización.
MÉTODOS BASADOS EN API KEY
En este caso los token obtenidos en el proceso de autenticación pueden ser empleados para manejar una tabla de autorización, en la que indicamos qué recurso puede ser usado por el usuario y para qué operación.
El problema sigue estando en que existe una relación directa entre la aplicación que consumirá la API y el usuario empleado para la autenticación.
Debido a esto, la aplicación debe gestionar si sus usuarios tienen permiso para ver y manejar la información que devuelve la API.
Lo ideal sería implementar en la API la gestión de la autorización, pero atendiendo a roles o grupos de permisos que puede hacer un usuario que solicita un recurso.
OAUTH 2.0
OAuth 2.0 (5) es un framework de autorización que se ha convertido en un estándar de facto en el uso de APIs.
Permite delegar la autorización de acceso a las APIs sin tener que proporcionar información del usuario.
Para ello se basa en el concepto de token de acceso, y define una serie de flujos y los casos de uso en que se aplican. Dependerá de nuestra API el flujo que debemos implementar.
Para comprenderlos es necesario que conozcamos un poco la terminología que se usa.
Los principales actores que intervienen en los flujos son:
- Propietario del recurso: Parte que puede autorizar el acceso a los recursos protegidos. Puede ser una autorización de ciertos recursos y de otros no. Generalmente es una persona.
- Cliente: Es la aplicación que accede a los recursos protegidos de un usuario con la autorización del mismo.
-
Proveedor / Servidor:
- Servidor de autorización: Valida usuario y credenciales; y genera tokens de acceso.
- Servidor de recursos: Es la API que expone los datos a los que se quiere acceder.
Figura 2 : Actores
El ámbito (scope) es un conjunto de parámetros que intervienen en la negociación de la autorización y consentimiento. Permite determinar a qué se solicita acceso y a qué se autoriza acceder.
Los tokens son credenciales usadas para acceder a recursos protegidos. Dependiendo de en qué fase de la negociación estemos, habrá diferentes tipos de token que se intercambiarán con los distintos actores.
Vamos cómo sería una flujo de información entre los actores:
Figura 3 : Abstract Flow
El primer paso es obtener permiso del propietario de la API para acceder a los recursos.
A este paso se le denomina Authorization Grant y existen cuatro flujos definidos (tipos de autorización).
Cada uno de los tipos de autorización está pensado para resolver un caso de negocio que podemos encontrar. Elegiremos uno u otro atendiendo al tipo de consumidor de nuestra API, el grado de confianza y el grado de interacción del usuario final en el proceso.
Veamos brevemente los distintos tipos de autorización.
Credenciales del cliente
En este caso el cliente pertenece al propietario del recurso, por lo que existe una relación completa de confianza entre los dos.
Por tanto se puede evitar la fase de comprobación de identidad, quedando el flujo reducido a solo dos pasos.
- La aplicación cliente envía sus credenciales al servidor de autenticación.
- El servidor de autenticación revisa las credenciales y si estos se corresponden con los de la aplicación cliente, se le remite el token de acceso.
Figura 4: Client Credentials
Este esquema solo se debe emplear en los siguientes casos:
- La aplicación consumidora es de total confianza y/o los datos que se remiten a los usuarios de la aplicación no son sensibles.
- Existe un acuerdo con el consumidor de la API y un canal seguro para transmitir las credenciales.
Credenciales del propietario del recurso
Este tipo de autorización se utiliza cuando la aplicación cliente es de total confianza.
Se emplean las credenciales del usuario para acceder a la API y establecer las autorizaciones de acceso a los recursos basados en las características de este usuario.
Estas credenciales no se almacenan en la aplicación cliente, y únicamente se utilizan para obtener un token de acceso.
Este tipo de autorización se usa sobre todo en aplicaciones móviles, donde una vez descargada la aplicación al terminal las credenciales se introducen una única vez.
Figura 5: Resource Owner Password Credentials
En este caso, el flujo sería:
- El usuario final proporciona sus credenciales directamente a la aplicación cliente, siendo la aplicación la que se encarga de autenticarse con esas credenciales.
- La aplicación envía las credenciales del usuario y el servidor devuelve el token.
- La aplicación gestiona el ciclo de vida del token y no vuelve a solicitar al usuario sus credenciales.
Este flujo se usará en los siguientes casos:
- Aplicaciones Web, móviles o de escritorio que sean confiables.
- El usuario consiente que sus credenciales sean empleadas para la interacción con el recurso.
- La API tiene control de la autorización del usuario.
- La comunicación es de tipo cliente-servidor.
Authorization Code
En este flujo el usuario final toma un papel relevante, dado que debe:
- consentir expresamente que la aplicación cliente pueda acceder a sus datos y confirmar que el token de autenticación es válido, y
- que se pueda remitir el token de acceso.
Se sigue evitando de esta forma que la aplicación cliente tenga acceso a las credenciales del usuario, sustituyendolos por una token de autenticación.
Figura 6: Authorization code
Veamos como funciona este flujo:
1.- El cliente comienza el flujo dirigiendo a la aplicación cliente al punto de autorización (una interfaz de login). La aplicación informa del alcance de autorización, y la dirección de retorno donde está la aplicación cliente.
2.- El servidor de autenticación identifica al propietario del recurso y establece si este autoriza al cliente a acceder.
3.- Si la autorización ha sido afirmativa, el servidor de autenticación redirige a la aplicación cliente enviando el token de autorización en la redirección.
4.- La aplicación cliente envía una petición al servidor de autenticación con el token recibido y sus credenciales para obtener el token de acceso.
5.- El servidor comprueba el token de autorización y las credenciales de aplicación, y remite el token de acceso.
Este flujo es especialmente empleado cuando:
- No se confía en la aplicación cliente, como pueden ser aplicaciones móviles o de escritorio.
- Cuando se quieren conectar la API a aplicaciones de terceros.
Autorización implícita
Este último caso es idéntico al anterior, pero en vez de emplear un token de autenticación se emplea directamente el token de acceso como respuesta.
Figura 7 : Implicit Grant
Vemos cómo se lleva a cabo este flujo:
- El cliente inicia el flujo direccionando al agente (por lo general el navegador web) del propietario del recurso hacia el endpoint del servidor de autorización. El cliente incluye el alcance de autorización, la dirección de retorno y el estado local.
- El servidor de autorización autentica al propietario del recurso y establece el acceso del cliente.
- El agente sigue la redirección basada en la url de retorno y esta incluye el token de acceso, que será almacenado y gestionado durante su ciclo de vida.
- Con el token de acceso, la aplicación cliente es capaz de acceder a los recursos.
Cuándo debemos emplear este flujo:
- El caso básico son las aplicaciones de una sola página (6), que al emplear solo el almacenamiento del cliente web, éste no se puede considerar un entorno seguro.
- Cuando el usuario final tenga que tener un control del acceso a los recursos y conocer dónde está accediendo la aplicación cliente.
Debemos indicar que este mecanismo no puede garantizar la confidencialidad del token de acceso, por lo que su tiempo de vida es muy limitado y no tiene posibilidad de renovación.
USAR UNA PLATAFORMA SEGURA
Llegados a este punto, hemos podido comprobar que habilitar la autenticación y autorización para nuestra API no es algo sencillo y que podamos obviar.
Aún quedan muchos otros aspectos de la seguridad que no hemos incluido y que son de igual importancia, referentes a escalabilidad, disponibilidad, contramedidas para denegación de servicio, etc…
Paremos por un momento y tengamos en cuenta una serie de recomendaciones básicas para abordar la seguridad de una API:
- Simplicidad: Debemos buscar la solución más simple y que mejor se ajuste al grado de seguridad que requiere nuestra API. Añadir complejidad innecesaria solo nos llevará a cometer errores.
- Usar siempre HTTPS: Esto evitará que el tráfico pueda ser fácilmente interceptado. Y si podemos usar HTTP 2, mucho mejor ya que mejorará el rendimiento.
- Usar encriptación para las contraseñas:evitaremos que se pueda identificar las contraseñas.
- Usar OAuth2 o JWT: son con diferencia los frameworks más usados y mejor documentados y soportados.
Con estas recomendaciones en mente, debemos pensar si compensa invertir esfuerzos en implementar todos los mecanismos de seguridad en nuestra propia plataforma.
Conviene valorar el uso de una solución Gateway que nos proteja y que facilite la gestión de la suscripción a nuestra API por los consumidores.
Quizás tengamos la posibilidad de delegar la mayoría de estos aspectos a una solución de terceros especializada que nos ayude a ahorrar tiempo y esfuerzo, y que nos permita centrarnos en la funcionalidad y usabilidad de nuestra API.
La plataforma que proporciona Nubentos en su API Marketplace para Sanidad, incorpora los principales mecanismos de seguridad comentados anteriormente y muchos otros específicos para casos de uso más especiales.
Pero además, aporta características adicionales relativas a la seguridad:
- Capacidad de escalado automático: La plataforma proporciona la capacidad de gestionar cualquier nivel de tráfico que recibe una API, para que pueda concentrarse en los servicios y la lógica de negocio, en lugar de en el mantenimiento de la infraestructura.
- Capacidad de gestionar listas de acceso: Podemos identificar atacantes y bloquearlos, no solo atendiendo a la IP de origen sino viendo el tipo de petición que realizan y actuando en consecuencia.
- Gestión de la calidad del servicio: Mediante los distintos mecanismos de gestión del caudal podemos limitar las peticiones que llegan a los proveedores de APIs para evitar saturar los sistemas. Podemos limitar las peticiones que un cliente único puede realizar, evitando de este modo usos malintencionados o fraudulentos.
- Proximidad al cliente: La plataforma API Marketplace de Nubentos cuenta con una arquitectura desplegada globalmente. Esto facilita que independientemente de donde estén su clientes dispongan de un punto de acceso cercano, reduciendo los tiempos de latencia y mejorando el tiempo de respuesta.
Todas estas características de seguridad avanzada, están a su alcance de forma gratuita en Nubentos, la mejor plataforma para abrir sus APIs para Sanidad a terceros de forma segura.
REFERENCIAS
(1 ) The Protection of Information in Computer Systems, by Jerome Saltzer and Michael Schroeder
(2) Architectural Styles and the Design of Network-based Software Architectures, by Roy Thomas Fielding
(3) Basic access authentication
(4) JSON Web Token (JWT) ( IETF )
(5) The OAuth 2.0 Authorization Framework
(6) Single-page application
(7) OAuth 2.0: equilibrio y usabilidad en la securización de APIs
(8) Conceptos básicos de oAuth2
0 comentarios