Gestión de reclamaciones
A continuación, tenemos que pensar cuidadosamente en las reclamaciones. Una reclamación es simplemente el par nombre/valor incrustado dentro de nuestros tokens de acceso e identificación. Por ejemplo, puedes tener un claim de user_id o email para que las aplicaciones downstream puedan usarlos para crear perfiles o tomar decisiones. La parte confusa es que la especificación de OAuth Core no introduce el concepto de reclamaciones o incluso incluye la palabra reclamación. Esto es útil porque podemos definir lo que necesitemos. Desgraciadamente, el reto es que la gente las definirá como necesite. La especificación JWT (RFC 7519) introduce el concepto y define una estructura básica, pero todavía no establece ninguna convención para los nombres, estructuras, etc.
Usar OpenID Connect nos protege bastante. Define un conjunto simple de reclamos para los detalles del usuario como el nombre, la dirección y similares. Si sólo usamos esos y limitamos el acceso según los ámbitos adecuados, el usuario sabe qué información está compartiendo y las aplicaciones saben cómo usarla.
Alternativamente, a medida que añadimos reclamos adicionales, el deseo natural es tener un identificador único para el usuario. Si somos cuidadosos, usamos una clave primaria ofuscada que no tiene significado fuera de nuestro sistema. Si no tenemos cuidado, podría ser un identificador de cliente, un número de empleado o incluso un número de la Seguridad Social. Esta es la misma situación en la que Facebook está luchando con las implicaciones de compartir demasiada información sobre la red de un usuario a través de su API.
Tenemos que ser reflexivos y considerar las consecuencias de la información que ponemos en nuestros tokens. Nunca debemos incluir datos «por si acaso» y, en cambio, esperar a los casos de uso específicos que decidamos apoyar. Cualquier otra cosa es arriesgada en el mejor de los casos e irresponsable en el peor.
Tipos de concesión – Cuándo y por qué
Si bien he saltado directamente a los ámbitos y reclamaciones, el otro error más común está relacionado con los tipos de concesión o flujos específicos de OAuth. Los cuatro tipos de grant -Código de Autorización, Implícito, Contraseña del Propietario del Recurso y Credencial del Cliente- definen cómo una aplicación puede recuperar tokens de su servidor OAuth y se utilizan en diferentes casos de uso.
Código de Autorización
El flujo de Código de Autorización es el más potente y el más seguro por defecto. Cuando la aplicación redirige al usuario al proveedor de identidad para autenticarse, el IdP le devuelve un código de autorización de corta duración y de un solo uso. La aplicación utiliza el código de autorización para recuperar el token de acceso.
La parte importante es doble: En primer lugar, cuando el usuario ve el código de autorización, éste ya se ha consumido y, por tanto, no puede volver a utilizarse. En segundo lugar, el token de acceso es guardado por la aplicación en el backend. Asumiendo que la aplicación está construida de forma segura, un usuario malicioso tiene que encontrar otra forma de atacarla.
Desgraciadamente, esto no funciona para las aplicaciones del lado del cliente, como muchas aplicaciones de Javascript o la mayoría de las aplicaciones móviles, ya que la propia aplicación puede ser atacada o descompilada para obtener información sensible. Por lo tanto, necesitamos un enfoque diferente.
Implícito
El flujo implícito está diseñado específicamente para aplicaciones móviles o aplicaciones Javascript del lado del cliente donde las credenciales incrustadas podrían ser comprometidas. La mecánica es sencilla en el sentido de que la aplicación redirige al usuario al Proveedor de Identidad para autenticarse, el IdP le devuelve token(s), y la aplicación lo utiliza según los ámbitos que tenga.
Dado que es bastante probable que el usuario pueda interactuar con el token(s), es importante que nuestros casos de uso lo reflejen. Si tenemos una aplicación bancaria, permitir el ámbito send_wire_transfers_to_russia puede ser una mala idea a menos que tengamos factores adicionales incorporados en nuestro proceso de autenticación para validar que el usuario correcto lo está utilizando. La próxima vez que pierdas tu teléfono, lo agradecerás.
Como resultado, esto se utiliza a menudo para los escenarios de OpenID Connect donde un usuario quiere proporcionar información de perfil de confianza a un tercero, pero no necesariamente el acceso o los permisos a otros sistemas. Dado que los conceptos subyacentes son los mismos y la implementación parece muy similar, es la mayor parte del beneficio para el mismo esfuerzo.
Contraseña de propietario de recurso
Comparado con los tipos de concesión anteriores, la contraseña de propietario de recurso me pone nervioso. Tanto con el código de autorización como con los flujos implícitos, la aplicación redirige al usuario al proveedor de identidad para que envíe su nombre de usuario y contraseña. Como resultado, la aplicación nunca ve sus credenciales. Con el flujo Resource Owner Password, la propia aplicación acepta las credenciales y las envía en nombre del usuario.
Si la aplicación es maliciosa o incluso sólo está mal desarrollada, podría almacenar esas credenciales y comprometer la información del usuario. Por lo tanto, sólo debe utilizar esto si está construyendo aplicaciones para que sus usuarios interactúen con sus sistemas heredados. Por ejemplo, un banco puede implementar esto para un portal interno de empleados.
Pero recuerda: Fundamentalmente, estás entrenando a los usuarios para que pongan sus credenciales en aplicaciones en las que pueden no confiar, lo cual es un mal hábito en el mejor de los casos y un riesgo de seguridad en todo momento.
Credencial de cliente
El tipo de concesión Credencial de cliente está diseñado exclusivamente para operaciones de servidor a servidor de backend. Piensa en ello como el nombre de usuario y la contraseña de un servidor. Conceptualmente, no está lejos de cómo su aplicación se conecta a otros sistemas de backend como su base de datos o Twilio. La ventaja es que tu proveedor de OAuth puede devolver información de configuración u otros detalles dentro del propio token.
Por último, como no hay un usuario involucrado, no es compatible con OpenID Connect.
En el cierre
Si bien todo este post ha sido sobre OAuth, probablemente has notado que no he incluido ningún código. La razón de ello es simple: Las decisiones de diseño siguen siendo más importantes.
Si tus alcances son demasiado amplios o tus reclamos incluyen información sensible o implementas el flujo equivocado para el entorno, las mejores librerías del mundo no te protegerán. La información de tus usuarios se verá comprometida, tus aplicaciones serán vulnerables y tu empresa sufrirá las consecuencias. Por el contrario, si entiendes los casos de uso de tu software y lo que tus usuarios intentan conseguir, tu software será mejor, más seguro, y podrás limitar los correos electrónicos de «Lo sentimos…» a tus clientes.
Para leer más
A partir de aquí podemos seguir adentrándonos en los protocolos, en las librerías individuales, o en grandes libros sobre el tema. Si quieres entender cómo encajan las RFCs individuales, echa un vistazo al libro de Aaron Parecki OAuth2.0 Simplified y a su acompañante Map of OAuth 2.0 Specs. Es mi hoja de trucos para los enlaces a las especificaciones clave y cuál cubre qué. Todo lo anterior inspiró mi guía de Prácticas Recomendadas para la Gestión de Acceso a la API que detalla los buenos principios de diseño y desarrollo para los Clientes OAuth, los Servidores de Autorización, las puertas de enlace de la API, y sus aplicaciones.