20
Entendiendo oAuth Una breve explicación sobre oAuth 1.0 [Type the author name] 4/28/2012 Este documento es una breve introducción a oAuth, comentando brevemente como funciona el procolo en su versión 1.0a y mencionando los distintos flujos de oAuth existentes

Entendiendo oAuth

  • Upload
    air4gb

  • View
    150

  • Download
    2

Embed Size (px)

DESCRIPTION

Entendiendo oAuth

Citation preview

Page 1: Entendiendo oAuth

Entendiendo oAuth Una breve explicación sobre oAuth 1.0

[Type the author name]

4/28/2012

Este documento es una breve introducción a oAuth, comentando brevemente como funciona el procolo en su versión 1.0a y mencionando los distintos flujos de oAuth existentes

Page 2: Entendiendo oAuth

EntendiendoOAuth

Contenido ¿Qué es OAuth? ........................................................................................................................ 2

La necesidad de OAuth .......................................................................................................... 2

Tokens, tokens, tokens.............................................................................................................. 3

Criptografía para dummies .................................................................................................... 3

Dos amigos... ..................................................................................................................... 4

...y el novio celoso. ............................................................................................................ 5

Firmas digitales ................................................................................................................. 6

Firma de peticiones en OAuth ............................................................................................... 8

Tipo de tokens OAuth ........................................................................................................ 9

Normalización de peticiones ........................................................................................... 11

Creación de la cadena base de firma ............................................................................... 12

El método de codificación percent encoding .................................................................... 12

Elementos de una petición OAuth ........................................................................................... 13

Parámetros OAuth .............................................................................................................. 13

Localización de los parámetros OAuth ................................................................................. 14

Cabecera Authorization ................................................................................................... 14

Flujos de OAuth ...................................................................................................................... 15

3-legged OAuth ................................................................................................................... 15

Cliente escritorio – Autenticación por PIN ........................................................................... 16

Cliente escritorio – autenticación por password .................................................................. 17

2-legged OAuth ................................................................................................................... 17

Pseudo-autenticación con OAuth ........................................................................................ 17

Desde ya hace un tiempo se oye hablar mucho de OAuth. Casi cualquier red social o aplicación web que exponga una API pública para desarrolladores expone sus servicios usando este protocolo. ¿Quieres integrarte con Twitter, Linkedin, Facebook o Google+, entre muchas otras? Todas ellas requieren usar OAuth para poder utilizar sus servicios. El objetivo de este documento no es que puedas aprender a crear un cliente que use OAuth, para ello no hay mejores tutoriales que los propios que desarrollan los creadores de servicios (créeme: ellos son los primeros interesados en que uses sus servicios). Tampoco es objetivo de este documento explicar todos los pormenores de OAuth (para ello hay una especificación

Page 3: Entendiendo oAuth

oficial). Entonces... ¿cuál es el objetivo? Pues simple y llanamente: que entiendas OAuth. Que entiendas qué es OAuth, cuál es su motivación, que problemas permite solucionar y que otros puede llegar a plantear. Por supuesto vamos a entrar en detalles sobre el funcionamiento de OAuth, aunque para descripciones detalladas referenciaremos a la RFC. Y sí, también veremos cómo crear un cliente OAuth y por encima de todo un proveedor de OAuth y cómo integrarlo en nuestras aplicaciones web usando, en este caso, ASP.NET MVC.

Si te interesa el tema, y quieres conocer OAuth en lugar de simplemente usarlo... este documento es para ti.

¿Qué es OAuth? Resumiendo, OAuth es un protocolo de autorización (su nombre proviene de Open Authorization), que permite a un usuario (propietario de ciertos recursos) autorizar a un tercero a que acceda a dichos recursos en su nombre pero sin darle en ningún momento a este tercero sus credenciales de autenticación (es decir, sin darle a este tercero su nombre de usuario ni contraseña).

Actualmente está en su versión 1.0a y se está desarrollando la versión 2.0 que va a ser incompatible con la versión anterior. Dicha versión 2.0 debería haberse finalizado a finales del 2011, pero sigue estando todavía en desarrollo y sin fecha prevista de finalización. La principal mejoras de OAuth 2.0 respecto a 1.0a son que es más fácil de usar para el usuario. Este documento se basa en OAuth 1.0.

Aun cuando OAuth es un protocolo de autorización es posible conseguir una pseudo autenticación con él, y de hecho uno de usos más extendidos es el de entrar en una aplicación web usando el usuario y contraseña de otra aplicación. De esta manera grandes proveedores de OAuth, como Facebook, se convierten a su vez en proveedores de autenticación de otras webs. Así, paradójicamente, OAuth está teniendo éxito donde otros protocolos más orientados a autenticación como OpenID o anteriormente Passport (actual Live ID) no han terminado de tenerlo. Esto nos demuestra una vez más, que el éxito de un producto (un protocolo en este caso) viene muchas veces marcado por quien lo adopta, y el momento en que lo adopta, más que en las características técnicas de éste. Esta es una lección que solemos olvidar demasiado a menudo.

La necesidad de OAuth La necesidad de un protocolo de autorización como es OAuth suele ser la confianza. O mejor dicho, la falta de ella. El hecho de que yo como usuario no confíe en una aplicación lo suficiente como para darle mis datos de autenticación pero por otro lado quiera permitir que dicha aplicación realice algo en mi nombre. Y no es lo mismo realizar algo en el nombre de alguien, que suplantar a este alguien. Esto es precisamente lo que permite OAuth: que alguien realice tareas en nombre de otro, pero sin poder suplantarlo: en todo momento se sabe quién es realmente el que está realizando las tareas. Al tener la autorización separada de la autenticación, yo puedo en cualquier momento desautorizar a quien yo haya autorizado previamente. Es decir, impedir que siga realizando tareas en mi nombre. Y puedo hacer esto sin necesidad de modificar mi usuario o contraseña.

Page 4: Entendiendo oAuth

Y desde el punto de un proveedor de servicios... ¿Qué le ofrece OAuth que motive el usarlo? Pues precisamente el hecho de querer generar un ecosistema de terceros que usen sus servicios. Pongamos como ejemplo a Facebook. Facebook no expone su API para su propia aplicación móvil, la expone básicamente para permitir todo un desarrollo de un ecosistema de aplicaciones integradas en Facebook, pero realizadas por otros. Es una relación win-win entre Facebook y el creador de la aplicación. El segundo puede aprovechar todo el potencial social que Facebook puede generar, y el primero obtiene más interacciones que es lo que más necesita una red social. Por supuesto que todo esto se podría conseguir sin OAuth, pero en unos tiempos donde se están mandando tantos (acertados) mensajes contra el phising y continuamente se nos dice que vigilemos nuestras credenciales y que no nos fiemos, no quedaría muy bien que cualquier web o aplicación nos pidiese el usuario y contraseña de Facebook... ¿Qué hará con ellos? ¿Cómo tengo yo la seguridad, como usuario, de que la aplicación es bienintencionada? Además, incluso en el caso de que la aplicación fuese bienintencionada, el que todas mis aplicaciones conectadas a Facebook tengan mi usuario y contraseña implica que si alguna vez, por cualquier razón, los modifico deba informar a todas esas aplicaciones de nuevo. Como veremos más adelante OAuth me permite obviar todo esto.

Así pues, OAuth expone claras ventajas tanto para usuarios como para desarrolladores de servicios. Ha llegado el momento de ver, someramente, como funciona.

Tokens, tokens, tokens La verdad es que OAuth va, básicamente, sobre intercambiar tokens. Hay tres roles que debemos considerar:

El cliente, que quiere acceder a un servicio en nombre de un usuario. Este cliente puede ser una aplicación web, móvil o de escritorio.

El proveedor de servicios, que provee el servicio al cual quiere acceder el cliente El autenticador que autentica los usuarios

Lo que OAuth define es como esos tres roles deben comunicarse entre ellos para que al final el cliente pueda acceder al servicio. Lo que no define OAuth es como el autenticador realiza su trabajo (es decir, como se autentica el usuario).

El objetivo final es que el cliente consiga lo que desde siempre se ha llamado Access token (aunque en la RFC decidieron modificar todos los nombres y lo llamaron Token Credentials). Enviando este token el cliente puede acceder a un recurso protegido en nombre del usuario que haya autenticado el autenticador.

Criptografía para dummies Antes de meternos de lleno en OAuth, dado que vamos a hablar de firma digital y métodos criptográficos de clave simétrica o asimétrica déjame que te hable un poco sobre conceptos elementales de criptografía. Si conoces que son los métodos de clave simétrica, asimétrica y la firma digital, eres libre de saltarte este apartado :) Y por supuesto, si encuentras todo el tema de la criptografía aburrido y falto de interés te lo puedes saltar también, en el fondo no es necesario conocerlo para poder usar OAuth... Aunque sí para entenderlo realmente, y como de eso se trata, si te apetece… ¡allá vamos!

Page 5: Entendiendo oAuth

Dos amigos... Imaginemos a dos amigos, Alice y Bob que quieren enviarse un mensaje codificado sin que nadie más pueda descifrarlo. Hay muchos mecanismos de encriptación que pueden utilizar, pero los podemos dividir en dos grupos: de clave simétrica y de clave asimétrica.

Los de clave simétrica son los primeros que nos vienen a la cabeza cuando pensamos en mecanismos de codificación. Tenemos una función (f) que dada una clave (K) y un texto a codificar (t) devuelve el texto codificado (t’). Entonces se cumple que:

(ܭ, (ݐ = ᇱݐ (ܭ, (ᇱݐ = ݐ

Es decir, para cifrar y descifrar se usa la misma clave.

Ahora supongamos que Alice y Bob quieren mantener una conversación privada y para ello deciden cifrarla. Lo primero que tienen que hacer es quedar de acuerdo en la clave a usar. Bastaría con un correo de Alice proponiendo la clave y uno de Bob aceptándola. A partir de este punto ambos usan la misma clave y la conversación puede tener lugar.

Si has arrugado la nariz cuando he mencionado que Alice envíe un correo con la clave es que has visto el punto débil de los métodos de clave simétrica: el intercambio de la clave. Es un punto muy delicado, ya que si alguien (un tal Mallory que os presentaré luego) descubre la clave, toda la conversación entre Alice y Bob está comprometida.

Es aquí donde entran en juego los mecanismos de clave asimétrica.

Dichos mecanismos se basan en algo muy simple (pero a la vez muy potente): la capacidad de generar dos pares de claves, ligadas de algún modo entre sí, de forma que al codificar algo con una de las claves se pueda decodificar con la otra y viceversa. Así pues si tenemos un par de claves, llamémoslas A y B, un texto (t) a codificar y una función (f) que dado una clave y un texto devuelve un texto codificado, se cumple que:

൫ܣ),ܤ, ൯(ݐ = ൫ܤ),ܣ, ൯(ݐ = ݐ

Y no sólo eso, si no que la relación NO es reflexiva:

൫ܣ),ܣ, ൯(ݐ <> ݐ ൫ܤ),ܤ, ൯(ݐ <> ݐ

Cada uno de ellos por separado y sin comunicárselo a nadie genera un par de claves (A,B). En este momento Alice tiene su par de claves y Bob las suyas. Posteriormente ambos se envían por mail una sola de esas claves (pongamos la A), a la que llamaremos la clave pública. La otra clave del par de claves, se la guardan para ellos mismos y no la dicen a nadie así que la llamaremos la clave privada. De hecho, cualquiera que más adelante quisiera enviar mensajes a Bob, como su amigo del instituto Charlie, debe pedirle a Bob que le dé la clave pública. Tan solo esa.

En este momento, Bob pondría enviar un mensaje a Alice, encriptado con la clave pública de ella. El resultado es un mensaje que solo puede decodificar quien posea la otra clave del par de claves. Y dado que Bob ha usado la clave pública de Alice, quien posee la otra clave del par de claves es la propia Alice: se trata de su clave privada. De este modo Bob ha conseguido

Page 6: Entendiendo oAuth

enviar un mensaje que solo Alice puede entender. ¿Y si ahora Alice quiere responder el mensaje? Pues muy simple: tan solo debe cifrarlo usando la clave pública de Bob, para que este al recibirlo use su clave privada y pueda descifrarlo.

Resumiendo, la idea es muy simple: se cifra el mensaje con la clave pública del receptor, el cual debe usar su clave privada (que solo conoce él) para descifrarlo.

Este sistema asegura cifrado y descifrado seguro de los mensajes (tan seguro como sea el algoritmo de encriptación que se use, pero eso es otra historia). Pero existe un riesgo que debemos tener presente.

...y el novio celoso. ¿Recordáis que antes mencionamos a Mallory? Dejadme que os lo presente: es el novio de Alice. Aunque es un buen tipo, es extremadamente celoso y como cree que Bob tiene intenciones poco honestas con Alice hace tiempo que está espiando lo que ella hace. En el fondo Mallory no le tiene manía a Bob: cree que todo el mundo quiere algo con Alice más allá de la amistad.

A priori puede parecer que el mecanismo de encriptación basado en clave asimétrica les protege del todo: la única clave que circula al principio de la conversación entre Alice y Bob es la clave pública de cada uno de ellos que solo sirve para cifrar, nunca para descifrar, así que aunque Mallory supiese la clave pública no podría hacer nada (a diferencia de un mecanismo de clave simétrica, ya que en este caso si Mallory descubre la clave puede descifrar toda la conversación). En efecto, es cierto que si Mallory tan solo conoce las claves públicas de ambos no puede comprometer la seguridad de la comunicación de los dos amigos... Pero esta certeza no es garantía de una seguridad absoluta.

Y es que Mallory instaló un proxy conectado a su propio ordenador que le permite tener acceso e interceptar todo lo que su novia envía y recibe desde internet (sí, los celos son muy malos). Gracias a esto Mallory intercepta el correo en el que Alice le pedía a Bob su clave pública y deja que llegue a Bob. Bob recibe el mensaje que proviene de Alice y le contesta con su clave pública. Dicho mensaje es interceptado de nuevo por Mallory, quien cambia la clave pública de Bob por la suya, se guarda la clave pública de Bob y reenvía el mensaje a Alice. En este punto Alice cree tener la clave pública de Bob, pero realmente tiene la de su novio.

Así cuando Alice quiere decirle algo a Bob, lo encripta con la clave pública de este... o con lo que ella cree que es la clave pública de Bob. Porque realmente es la de Mallory, el cual puede descifrarlo (usando su clave privada), modificarlo, cifrarlo de nuevo (usando la clave pública de Bob que se ha guardado antes) y reenviar el mensaje a Bob, quien creerá que el mensaje proviene de Alice.

Este tipo de ataques, en el cual un tercero (Mallory) puede interceptar, leer y modificar mensajes que se envían un par de actores (Alice y Bob) sin que ninguno de ellos pueda saber que su seguridad ha sido comprometida se llaman ataques Man-in-the-Middle.

El error de Bob y Alice ha sido permitir que Mallory interceptara un único mensaje: el que usaron para intercambiar sus claves. Este es el punto débil de todo sistema de criptografía: el intercambio de claves (sí, incluso en los asimétricos donde podríamos creer que evitaban este problema).

Page 7: Entendiendo oAuth

Amigo lector, por si lo has pensado, una solución muy rápida que evitaría los trapicheos de Mallory, sería evitar que hubiese intercambio de claves públicas al inicio de la conversación entre Bob y Alice. Si ambos publicasen su clave pública en una web, a la vista del todo el mundo, Mallory no podría interceptar ningún mensaje y sustituir las claves porque este mensaje no existiría: cuando Alice quisiera ver la clave pública de Bob la miraría en esta web y viceversa. Claro que en este caso tanto Alice como Bob deben tener estar seguros de que la web donde publican sus claves públicas es de confianza. No vaya a ser que le encarguen hacer la web a Chuck, un antiguo compañero de fiestas de Mallory, con lo que estarían igual que antes. Pero si la web es de una empresa que ofrece este servicio (hospedar claves públicas), y que ofrece absolutas garantías de seguridad, entonces sí que Mallory no tiene nada que hacer y Alice y Bob pueden estar tranquilos... Y aunque pueda parecer muy tonto, esto de publicar las claves públicas de todos en un sitio común, es más o menos lo que hacemos actualmente con los certificados digitales y las infrastructuras de clave pública (PKI).

Firmas digitales Si has entendido como funciona la encriptación, ya estás listo para comprender como funciona la firma digital. El concepto de firma digital es extremadamente sencillo: se trata de aplicar una función de hash al documento y cifrar tan solo el hash. El hash cifrado constituye la firma digital.

Funciones de hash Si Bob quiere enviar un documento firmado digitalmente, debe calcular el hash de este documento. El hash no es más que aplicar una función que devuelva un valor resumen que dependa de los datos del documento. Lo de resumen viene porque generalmente el tamaño en bytes del documento suele ser superior al tamaño en bytes del hash.

Así una posible función de hash sería sumar los códigos ASCII de todos los caracteres del documento y realizar el módulo 256. Con esto obtendríamos un número de 0 a 255. Fijaos que convertimos textos de cualquier número de byes a valores de un solo byte, de ahí lo de resumen. Dada esa función de hash, el hash del texto Hola seria 132.

Por supuesto esta es una función de hash horrorosa, seguro que no te cuesta nada encontrar otro texto distinto que dé el mismo valor de hash. Es evidente que, por norma general, siempre habrá más documentos que hash posibles (en nuestro caso hay infinitos documentos posibles y tan solo 256 hash), por lo que habrá colisiones (es decir dos documentos distintos que generen el mismo hash). Lo que distingue una buena función de hash de una de mala es lo que cueste encontrar dos documentos distintos que generen un mismo hash (lo que en criptografía se conoce como resistencia a las colisiones y que mide cuan resistente es una función de hash frente a lo que se conoce como un ataque de cumpleaños).

Suponiendo una función de hash con alta resistencia a las colisiones (es decir que sea inviable encontrar dos elementos que den el mismo hash) entonces Bob puede firmar un documento de la siguiente manera:

1. Calcula el hash del documento 2. Cifra el hash y obtiene la firma digital. 3. Envía el documento junto con la firma digital.

Page 8: Entendiendo oAuth

Lo importante aquí es que el documento no tiene por qué estar encriptado (puede estarlo pero no es obligatorio). Lo que está cifrado usando la clave privada de Bob es el hash y eso constituye la firma digital. Cuando el receptor reciba el documento debe:

1. Descifrar la firma digital para obtener el hash 2. Calcular por su parte el hash del documento (usando la misma función de hash) 3. Comparar ambos valores (el hash descifrado y el hash calculado)

Si ambos valores coinciden la firma digital del documento es válida… ¿y qué significa exactamente esto? Pues depende del mecanismo de cifrado que se use para cifrar el hash.

Firmas con mecanismos asimétricos vs firmas con mecanismos simétricos A grandes rasgos: una firma digital correcta indica que el documento no ha sido modificado por nadie a excepción de un remitente válido y que ha sido enviado por un remitente válido. Lo que significa exactamente “remitente válido” varía en función de si para cifrar el hash se usó un mecanismo con claves simétricas o asimétricas.

Si se ha usado un mecanismo con claves asimétricas, remitente válido es aquel que ha enviado el documento. Nadie más. Debe notarse que decimos aquel que ha enviado el documento, no aquel que legítimamente puede leerlo. Si en el ejemplo anterior Bob hubiese usado un mecanismo de cifrado asimétrico podemos afirmar que el documento no ha sido alterado (lo que se ha recibido es lo que se ha enviado) por nadie más. No solo eso, si no que además se puede asegurar que ha sido Bob quien lo ha enviado (o dicho a la inversa, Bob no puede negar haber enviado el documento, lo que se conoce como no repudio). Si alguien intercepta el documento y lo modifica, dado que no puede modificar la firma digital (ya que está cifrada con la clave privada de Bob que tan solo tiene él), cuando el receptor reciba el mensaje el hash que él calcule diferirá del que venía con el documento, con lo que se sabrá que ha sido interceptado y modificado.

Si se ha usado un mecanismo de clave pública, entonces “remitente válido” significa cualquiera que conozca la clave. Es decir cualquiera que pueda recibir un mensaje y calcular la firma digital. Si Bob calcula su firma digital cifrando el hash con un mecanismo de clave simétrica, es evidente que Alice debe conocer la clave para poder descifrar el hash y compararlo con el que obtenga ella para validar la firma digital. Pero dado que la clave que se usa para descifrar es la misma para cifrar y que Alice también la tiene, nada impide que Alice modifique el documento, vuelva a calcular el hash y lo cifre de nuevo usando la misma clave. En este caso no podemos pues asegurar unívocamente como antes que lo ha enviado Bob. Puede haberlo enviado Alice. No hay manera de saberlo. La firma digital sigue asegurando, eso sí, que si el mensaje es modificado por alguien que no conoce la clave de cifrado, el resto de participantes que sí la tienen se darán cuenta de que el mensaje ha sido modificado. Digamos que, usando un mecanismo cifrado de clave simétrica, todos los participantes válidos son tratados como una misma persona.

Seguridad de la firma digital Fíjate que la asunción principal que se realiza de la firma digital (se puede asegurar que el documento no ha sido modificado), depende directamente de que la función de hash tenga una alta resistencia a las colisiones. De hecho lo que debe evitarse es que sea factible para alguien generar un par de documentos (uno auténtico y otro fraudulento) que tengan el

Page 9: Entendiendo oAuth

mismo hash1. Si eso es factible (a nivel computacional) de realizar, alguien, llamémosla Carol, podría presentar el documento auténtico a Bob, quien lo firmaría y luego podría añadir la firma digital de Bob al documento fraudulento, con lo que a todos los efectos sería como si Bob hubiese firmado dicho documento falso.

El propósito de la firma digital no es evitar que alguien intercepte el mensaje, si no asegurar que éste no ha sido alterado en tránsito y que es enviado realmente por el remitente. Si se quiere evitar que el mensaje sea visible a terceros, este debe además cifrarse. Eso sí, que quede claro: La firma digital no evita que pueda existir un Man-in-the-middle si el intercambio de claves ha sido comprometido.

OAuth permite usar tanto mecanismos de clave simétrica como mecanismos de clave simétrica para cifrar el hash y obtener la firma digital. A la práctica la mayoría de proveedores soportan tan solo un mecanismo de clave simétrico (HMAC) para evitar todo el proceso de negociación de claves públicas. Aunque es un poco menos seguro (cualquiera que robe la clave que se use para cifrar los mensajes podrá enviar mensajes OAuth válidos) evita todo el trasiego de intercambio de claves públicas.

Firma de peticiones en OAuth En OAuth todas las peticiones que realiza el cliente van firmadas digitalmente. La especificación habla explícitamente de tres métodos de firmado:

1. HMAC-SHA1: Que es un método de firma electrónica basado en la función de hash SHA1 y el método de cifrado simétrico HMAC

2. RSA-SHA1: Que es un método de firma electrónica basado en la función de hash SHA1 y el método de cifrado asimétrico RSA. La especificación no dice nada sobre como el cliente y el proveedor de servicios intercambian sus claves públicas.

3. PLAINTEXT: No existe firma digital. El valor de la firma digital se sustituye por el valor de los tokens secretos (Consumer Secret, Request Secret y Access Secre) que se usen en cada momento. Este método es altamente inseguro y de hecho la propia especificación ya indica que debe usarse sobre un canal de comunicación seguro (SSL o TLS) y tiene su razón de existir en que si se usa uno de esos canales, no es necesario añadir un método adicional como la firma electrónica para garantizar que la petición no ha sido modificada, dado que el propio canal seguro te lo asegura.

Honestamente, en la especificación no queda muy claro si debe darse soporte a esos tres métodos o bien puede darse soporte a solo algunos de ellos. Lo que sí dice es que pueden añadirse métodos adicionales. En la vida real, hay muchos proveedores de OAuth que no soportan RSA-SHA1 supongo que para evitar el problema de intercambio de claves públicas, algo que se evita en HMAC-SHA1 al ser este un método asimétrico donde hay una sola clave compartida y conocida por todos. Personalmente creo que implementar solo HMAC-SHA1 es una solución más que válida-

1 Esto es importante: no es peligroso que varios documentos tengan el mismo hash (esto es inevitable, de hecho). Lo que es peligroso es que sea factible computacionalmente para alguien generar pares de documentos con el mismo hash.

Page 10: Entendiendo oAuth

La necesidad de que en OAuth cada petición vaya firmada es, evidentemente, por seguridad: si no fuese así, alguien podría interceptar la petición del cliente al proveedor de servicios, modificarla y reenviarla de nuevo. Precisamente para evitar esto y asegurar que el proveedor de servicios solo responde a peticiones legítimamente enviadas por un cliente, estas deben ir firmadas. Esto no evita que alguien pueda ver los datos que se envían entre cliente y proveedor pero sí evita que puedan ser modificados.

Es importante destacar que la respuesta del proveedor de servicios no va firmada (esto es así debido a la naturaleza síncrona de http): tan solo se firman las peticiones del cliente. Exacto: alguien con un sniffer podría modificar las respuestas del proveedor de servicios y el cliente no se daría cuenta, pero para evitar este escenario ya hay otras alternativas de seguridad adicionales a OAuth (SSL o TLS sin ir más lejos). Este no es un escenario que intente resolver OAuth. Quede claro pues que OAuth no es un protocolo de seguridad, ni quiere, ni puede, garantizar la seguridad o integridad de los datos enviados o recibidos.

Cuando empieces a leer sobre OAuth, verás que continuamente se habla de pares de tokens: el token público y el secreto (key y secret en inglés). No te confundas: esos pares de tokens, ¡no son pares de claves asimétricas! Realmente uno de ellos (el público) actúa como identificador y el otro (el secreto) es el que se usa para firmar digitalmente.

Tipo de tokens OAuth

Consumer Key y Consumer Secret Por lo tanto todo cliente que quiera usar OAuth deberá tener su par de tokens. Quien otorga estos tokens y como estas son transferidas al cliente está fuera de la especificación de OAuth. Es decir, OAuth no define ningún mecanismo para que el cliente obtenga su par de tokens. Simplemente se asume que las tiene, y que ambos tanto cliente como proveedor de servicios las conocen.

En terminología OAuth llamamos Consumer Key al token que identifica un cliente y Consumer Secret al token privado que este cliente usará para firmar sus peticiones OAuth. Aunque desde siempre se han llamado así, en la RFC decidieron modificar el nombre y llamarlos Client Credentials (credenciales de cliente) nombre que realmente es más acertado.

La especificación no dice nada acerca de como el cliente obtiene sus credenciales, pero en la práctica lo más normal es tener que registrar el cliente manualmente, en el proveedor de servicios.

Page 11: Entendiendo oAuth

Ilustración 1: Registro de una aplicación cliente en Twitter

La Ilustración 1 muestra el proceso de registro de un cliente en Twitter. Una vez registrado el cliente Twitter nos informará de nuestras credenciales de cliente, que son las que deberemos usar. Este método es sencillo y eficaz aunque obliga a registrar cada posible cliente de forma manual. Tanto Facebook, como LinkedIn como cualquiera de los proveedores de OAuth ofrecen un mecanismo similar para el registro de clientes.

Request Token y Request Secret El objetivo final de OAuth es permitir acceder a recursos protegidos en nombre de un usuario en concreto. Para ello, el cliente debe a partir de sus credenciales de cliente, obtener unos tokens finales que representen que el usuario ha dado permisos para acceder a esos recursos. Para ello el primer paso es obtener un par de tokens temporales, que servirán para ir enlazando toda la serie de peticiones OAuth que son necesarias para obtener los tokens definitivas (mucha gente se refiere a esa serie de peticiones con el nombre de OAuth Tokens dance).

Page 12: Entendiendo oAuth

El Request Token identifica a una petición de permisos para un usuario en concreto. Cuando el cliente quiere obtener un token de acceso definitivo, lo que obtiene primero es el Request Token. Luego manda este Request Token al autenticador, quien (si el usuario acepta los permisos) le devuelve un código de verificación que luego el cliente puede usar para obtener los tokens finales (no te preocupes si eso te parece muy lioso ahora, luego aclararemos completamente el flujo OAuth). Lo importante es que te quedes con la idea de que el Request

Token y el Request Secret son tokens temporales, que son descartados una vez se obtienen los definitivos.

A lo mejor te estás preguntando por que es necesario un Request Secret. ¿No se supone que las peticiones van firmadas usando el Consumer Secret como clave para generar la firma digital? La respuesta es que una vez tenemos Request Token, las peticiones OAuth que hagamos irán firmadas usando el Consumer Secret y el Request Secret (ambos a la vez).

¡Ah sí! Se me olvidaba: He usado los nombres Request Token y Request Secret que son los que se usan comúnmente, pero la RFC usa otros nombres que son (de nuevo) mucho más acertados: Temporary Credentials.

Access Token y Access Secret El Access Token y el Access Secret (llamados en la RFC Token Credentials) son el objetivo final: los tokens que se obtienen una vez el usuario se ha validado y ha aceptado los permisos demandados por el cliente. Una vez el cliente obtiene esos tokens, el flujo de OAuth termina y el cliente puede empezar a realizar llamadas al proveedor de servicios en nombre del usuario.

El Access Secret se usa para firmar todas las peticiones OAuth que haga el cliente una vez tenga el Access Token (se usa conjuntamente con el Consumer Secret).

Ahora que ya conoces los tres pares de tokens de OAuth... viene la pregunta clave: ¿qué datos de la petición se firman?

Normalización de peticiones La firma digital de un documento (en nuestro caso de una petición http) depende de los datos que esta contenga. Debemos preguntarnos pues ¿qué define a una petición http?

El primer elemento es la URL, dos peticiones serán distintas si su URL es distinta. Eso significa que peticiones que solo difieren en la URL (incluso si van a URLs sinónimas como pueden ser http://www.krasis.com y http://217.130.23.249) van a generar firmas digitales distintas.

Otro elemento son los parámetros de la petición. HTTP permite que las peticiones lleven parámetros en varios sitios (query string, cuerpo, headers varios), así que OAuth define cuales son los posibles orígenes de los parámetros. En concreto se tomarán:

1. Los parámetros de la query string 2. Los parámetros en el cuerpo de la petición si esta viene como application/x-www-

form-urlencoded 3. El valor del header Authorization, si este define que es de tipo OAuth, excluyendo el

valor de realm si lo hubiese.

Page 13: Entendiendo oAuth

Nos queda un tercer elemento. Podemos tener dos peticiones exactamente con la misma URL, con los mismos parámetros (en el mismo orden y situación si se quiere) pero que sean dos peticiones distintas si usan un verbo http distinto.

Esos tres elementos se combinan en una cadena, que es la que se llama cadena base de firma (signature base string) y será esta cadena la que se firme digitalmente. Así pues la cadena base de firma incluye todo lo que es relevante de una petición http: su verbo, su URL y sus parámetros.

El proceso de conseguir la cadena base de firma a partir de una petición de http se conoce como normalización de peticiones. Y es que, como veremos ahora, peticiones distintas, pero que signifiquen lo mismo, van a generar la misma cadena base de firma. ¿A que me refiero con peticiones no idénticas pero que signifiquen lo mismo? Pues que tengan los mismos parámetros pero en orden distinto, o que la URL sea igual pero difiera en mayúsculas o minúsculas.

Creación de la cadena base de firma Para obtener esta cadena a partir de una petición http, debemos realizar unos pasos sencillos, pero de vital importancia (si nos equivocamos en esto, nuestra cadena base diferirá de la que calcule el proveedor de servicios y por lo tanto la firma digital será distinta, generando una petición inválida):

1. Obtener el verbo http usado, en mayúsculas (p.ej. POST o GET). 2. Obtener la URL normalizada. Esto significa que la URL se pasa toda a minúsculas. El

valor del host y del port debe coincidir con el valor de la cabecera “Host”. La ruta hasta la query string se añade tal cual. El puerto se incluye solo si no es el estándar (80 para http o 443 para https).

3. Obtener una cadena con todos los parámetros de la petición. Para ello con independencia de donde estén (query string, cuerpo de la petición o cabecera Authorization) se ordenan por orden alfabético y se concatenan uno tras otro (nombre=valor). Si dos parámetros tienen el mismo nombre, se ordenan por su valor. Si un parámetro está vacío, aparece igualmente sin valor.

4. Se codifica la URL normalizada, siguiendo un procedimiento propio, llamado percent encoding.

5. Se codifica la cadena con todos los parámetros de la URL, siguiendo el mismo procedimiento anterior

6. Se crea una cadena con el valor de 1, el símbolo &, el valor de 4, el símbolo & y el valor de 5.

Esta cadena obtenida en el punto 6 es la cadena base de firma, y de la cual se calculará el hash para obtener la firma digital de la petición.

El método de codificación percent encoding Este método se usa solo para el cálculo de la cadena base de firma. Es un método muy parecido y basado en el método de codificación de URIs (definido por la RFC 3986 en su apartado 2.1). La RFC de OAuth 1.0, en su sección 3.6 define claramente como es esta codificación:

1. Se codifica la cadena en UTF8

Page 14: Entendiendo oAuth

2. Los siguientes caracteres: letras, números, “-“,”.”,”_” y “~” no son codificados y se ponen tal cual.

3. Cualquier otro carácter debe ser codificado usando %xx, donde xx es el código hexadecimal, en mayúsculas, del byte.

Aunque el método parece idéntico al definido por el RFC 3986 en su apartado 2.1 no lo es. Hay una sutil diferencia: en OAuth se codifican todos los caracteres excepto los indicados en el punto 2. Mientras que en el RFC 3986 algunos caracteres no se codifican si actúan como separadores. Es un detalle importante. P.ej. la URL http://www.krasis.com codificada según la RFC 3986 es: http://www.krasis.com, mientras que usando el percent encoding de OAuth, los caracteres “:” y “/” se codifican igualmente, aun cuando forman parte del separador :// que separa protocolo de host. Así pues la URL queda como http%3ª%2F%2Fkrasis.com

Así pues cuidado con usar métodos que codifiquen URLs, incluso aunque sean conformes al RFC 3986, ya que puede ser que no generen exactamente la misma cadena.

Elementos de una petición OAuth Toda petición que llamemos petición OAuth deberá contener algunos elementos obligatorios que son los parámetros OAuth y la firma digital. No todos los parámetros son obligatorios en todo momento.

El protocolo define un conjunto de elementos que toda petición OAuth debe tener, y que sirven para garantizar el buen funcionamiento de éste. Los que deben existir en toda petición OAuth son:

1. El identificador del cliente (Consumer Key). 2. Un timestamp: Usualmente el número de segundos desde el 01 de Enero de 1970. 3. Un número único (nonce) 4. El método de firma digital usado 5. La firma digital

Luego, en algunas peticiones OAuth puede existir:

6. El identificador temporal (Request Token) 7. El identificador de acceso (OAuth Token)

De todos estos elementos el punto 3 merece especial atención, por lo ambiguo de su definición. Realmente la especificación no dice mucho acerca de él, salvo que no tiene ni porque ser un número y que su uso está recomendado para poder discernir entre dos peticiones distintas dado un mismo timestamp. O sea que dos peticiones con el mismo timestamp y del mismo cliente, deben tener un valor de nonce. La especificación no dice si deben ser secuenciales o no, ¡de hecho ya hemos comentado que no tiene ni porque ser un número! Cada proveedor puede establecer sus reglas y los clientes deben adaptarse a ellas. De hecho su uso no es obligatorio, depende de cada proveedor de servicios.

Parámetros OAuth El nombre de los distintos parámetros OAuth está definido por el protocolo y son los siguientes:

Page 15: Entendiendo oAuth

1. oauth_consumer_key: Identificador del cliente (Consumer Key) 2. oauth_timestamp: Timestamp de la petición 3. oauth_nonce: Valor del número único 4. oauth_signature_method: Contiene el tipo de método de firma digital que se usa. 5. oauth_signature: Contiene la firma digital de la petición 6. oauth_token: Contiene o bien el Request Token o bien el Access Token (en función del

paso del flujo en el que nos encontremos).

Adicionalmente a estos parámetros existen otros que se usan en momentos puntuales y que son los siguientes:

7. oauth_callback: URL que debe llamar el autenticador con el código de verificación en el flujo 3-legged OAuth.

8. oauth_token_secret: Credencial temporal privada / Access token privado (en función del paso del flujo en el que estemos) que nos devuelve el proveedor de servicios.

9. oauth_verifier: Código de verificación que devuelve el autenticador

Al margen de esos se pueden definer parámetros adicionales y esos pueden empezar por oauth_ si así se desea (la especificación no lo prohíbe).

Localización de los parámetros OAuth Estos elementos se pueden incluir en distintas partes de la petición:

1. En el querystring

2. En el cuerpo de la petición (si el content type es application/form-www-urlencoded)

3. En la cabecera Authorization, si esa indica que contiene datos OAuth. Esa es la manera recomendada por la especificación.

La especificación señala que un proveedor OAuth debe soportar los parámetros OAuth en cualquier de esas partes de la petición y que debe vigilar que no haya elementos duplicados (p.ej. un parámetro oauth_nonce en query string y otro en la cabecera Authorization). Si se encuentran elementos duplicados debe devolverse un error, en lugar de usar uno de los dos en función de cualquier posible criterio de prioridad.

Cabecera Authorization Como se ha mencionado, la manera preferida es en la cabecera Authorization, según muestra este ejemplo sacado de la propia RFC:

Authorization: OAuth realm="Photos", oauth_consumer_key="dpf43f3p2l4k3l03", oauth_signature_method="HMAC-SHA1", oauth_timestamp="137131200", oauth_nonce="wIjqoS", oauth_callback="http%3A%2F%2Fprinter.example.com%2Fready", oauth_signature="74KNZJeDHnMBp0EMJ9ZHt%2FXKycU%3D"

La cabecera Authorization debe indicar que es de tipo OAuth y el parámetro realm de aparecer se ignora a efectos de OAuth.

Page 16: Entendiendo oAuth

Como se puede ver el formato es nombre=”valor” (el valor está entrecomillado). Si un parámetro tiene un valor vacío debe aparecer nombre=”” (dos comillas dobles seguidas). Estríctamente hablando entre el nombre del parámetro y el signo de igual no se admiten espacios. Al igual que entre el signo de igual y la primera de las dos comillas dobles. Los parámetros van separados por una coma y un salto de línea opcional. Lo que es importante es que el valor del parámetro está codificado usando Percent Encoding (ver el valor del parámetro oauth_callback para un ejemplo).

En la RFC (apartado 3.5.1) se especifica con todo lujo de detalles el formato de la cabecera Authorization.

Flujos de OAuth Vamos a explorar los diversos flujos de OAuth que existen. La especificación en sí define un solo flujo, el conocido como 3-legged OAuth, pero vamos a explorar algunos flujos más que se pueden encontrar en distintos proveedores (como linkedin o twitter). Dos de ellos están pensados para aplicaciones de escritorio (o móviles) otro es para el caso de que queramos ejecutar servicios pero en nombre de ningún usuario en concreto y finalmente hablaremos sobre la pseudo-autenticación usando OAuth (el famoso “sign with Facebook” que se ve en numerosas web).

Esos flujos se diferencian tan solo por la forma en que el cliente (ya sea otra web o una aplicación de escritorio) consigue los tokens OAuth definitivos). Empecemos por el flujo definido por la propia especificación

3-legged OAuth Este es el flujo más conocido de OAuth y por el cual realmente fue creado. En este caso se asume que el cliente es capaz de tener un endpoint accesible para que el autenticador le pueda enviar el código de verificación. Evidentemente esto solo es posible si el cliente es una aplicación web. Pero vayamos paso a paso...

El primer paso es que el cliente realice una petición OAuth para pedir un par de tokens temporales. Esos tokens temporales (conocidos comúnmente como request token and secret) son los que usarán en todo el flujo hasta terminar obteniendo los tokens definitivos (conocidos como access token and secret). Para obtener estos tokens el cliente básicamente se identifica a si mismo (usando su consumer key) y envía un parámetro llamado oauth_callback que es a donde debe recibir el código de validación que le servirá para obtener los tokens definitivos.

El proveedor de servicios responde a dicha petición con los tokens temporales contenidos en los parámetros oauth_token y oauth_token_secret. ¡Todo el proceso ya se ha puesto en marcha!

Ahora el cliente debe llamar al autenticador pasándole el Request Token que ha recibido. Esta petición, como va contra el autenticador y no contra el proveedor de servicios no es una petición OAuth. Es decir, el cliente no se identifica a sí mismo, ni la petición va firmada. El autenticador comprueba que el token temporal es válido, mira cual fue el cliente que lo solicitó (el proveedor de servicios debe haber guardado esta información en algún sitio accesible para el autenticador) y entonces pueden suceder varias cosas:

Page 17: Entendiendo oAuth

1. Que el token temporal pasado no sea válido: Se muestra un mensaje de error al usuario.

2. Que el token temporal sea válido y que el usuario NO esté autenticado contra el autenticador. El usuario recibirá el formulario de login del autenticador donde se le pedirán sus credenciales y que acepte dar permisos a la aplicación indicada. Si el usuario se autentica y da los permisos se sigue al punto 4.

3. Que el token temporal sea válido y el usuario esté autenticado. Si el usuario NO había dado permisos a la aplicación indicada se le pedirá que le de esos permisos. Si el usuario ya los había dado se seguirá al punto 4.

4. El autenticador redirige al usuario a la dirección de callback que especificó el cliente en la primera petición. La dirección de callback recibirá dos parámetros: el token temporal y un código de verificación.

¡Ya casi estamos! Una vez el cliente recibe en su dirección de callback una petición, junto con un token temporal y un código de verificación debe:

1. Asegurarse que el token temporal es el mismo que él ha generado 2. Realizar una petición OAuth al proveedor de servicios mandándole el token temporal

(Request Token) y el código de verificación. La respuesta a esta petición OAuth serán los tokens finales (Access token and secret) que se usan para identificar llamadas OAuth en nombre del cliente autenticado.

Cliente escritorio – Autenticación por PIN Cuando el cliente es una aplicación de escritorio el proceso es un poco más pesado para el usuario, ya que el cliente no puede especificar una dirección de callback. En este caso se usa lo que se llama out-of-band configuration. El tema está en que la especificación lo menciona explícitamente, pero luego no dice nada más acerca de este modo de configuración. Así que este apartado está basado en cómo se ha implementado en Twitter. Este método es válido para aplicaciones que pueden abrir una ventana de navegador (aunque no puedan interaccionar con ella).

La primera petición es idéntica al flujo tradicional, salvo que el valor de oauth_callback debe ser oob. Este valor está reconocido por la especificación para indicar que el cliente quiere usar el método de configuración out-of-band. La respuesta del proveedor será, igual que antes, el par de tokens temporales (Request Token y Request Secret).

La segunda petición del cliente será contra el autenticador. Puede ser que se use el mismo endpoint que el caso anterior, o puede que no. Dependerá de cada implementación, aunque lo normal es que se usen endpoints distintos del autenticador para poder personalizar el comportamiento de éste en cada caso. El comportamiento del autenticador debe ser el mismo que en el flujo anterior, aunque son posibles algunas variantes. P.ej. Twitter obliga a aceptar de nuevo los permisos incluso aunque se hubiesen aceptado previamente para el mismo cliente.

La principal diferencia con el flujo 3-legged es que una vez el usuario se autentica y da los permisos a la aplicación, al no haber dirección de callback a la que redirigir el usuario, el autenticador mostrará una página especial con un código (PIN) que el usuario deberá entrar a la aplicación.

Page 18: Entendiendo oAuth

El usuario entra el código PIN a la aplicación, y la aplicación usa este código PIN como si fuese el código de verificación: es decir, realiza una llamada OAuth al proveedor de servicios con el Request Token, el PIN entrado por el usuario y obtiene los tokens OAuth definitivos.

Cliente escritorio – autenticación por password Otro flujo posible para aplicaciones cliente que no pueden mostrar ni una ventana de navegador, es mandarle al autenticador el login y password del usuario. Claro que eso implica violar uno de los principios de OAuth: que el cliente nunca tiene acceso al login y password del usuario. En este caso el usuario debe introducir su login y su password, pero solo una vez, después la aplicación cliente no los usa nunca más, ya que el resto de peticiones son OAuth. Por supuesto estamos ante un tema de confianza de la aplicación. Si yo me descargo la aplicación oficial de Facebook, pongamos por caso, no tendré problemas en introducir mi login y password en ella. Si me descargo una aplicación realizada por Hackers. Inc. Pues seguramente no la entraré si me la pida (aunque la aplicación pueda ser legítima, yo no tengo manera de saberlo).

Como siempre el primer paso del flujo es idéntico: una petición OAuth del cliente para obtener los tokens temporales, mandando “oob” como valor de Oauth_callback.

Una vez tiene los tokens temporales, el cliente debe puede llamar al autenticador, pasándole el Request Token junto con el login y el password del usuario. El autenticador comprueba las credenciales y en caso de que sean correctas, responde con el código de verificación (debe notarse que el autenticador asume que el usuario da permisos a la aplicación, cosa lógica teniendo en cuenta que ha entrado su login y password en ella).

La aplicación una vez tiene el código de verificación, reanuda el flujo normal: manda el código de verificación junto el token temporal al proveedor de servicios para obtener los tokens definitivos. A partir de este punto todas las llamadas pueden ser OAuth y el login y password del usuario se pueden descartar.

2-legged OAuth Hay mucha confusión sobre que es 2-legged OAuth y existe básicamente porque es una forma de usar OAuth que no se menciona nunca en la especificación, donde una aplicación autoriza a otra aplicación a utilizar recursos protegidos, pero en este caso no se está involucrando a ningún usuario. Todo el flujo de adquisición de tokens desaparece: si el cliente está registrado en el proveedor (es decir tiene su par de claves) en lugar de usar el flujo normal y solicitar un par de tokens temporales, lo que hace es:

1. Realizar una llamada OAuth, usando su clave pública como Access Token (y firmando con el Client Secret).

El proveedor de servicios puede verificar que la clave pública pertenece a un cliente registrado y conocido, puede verificar la firma y si esa es correcta ejecuta la petición. En este caso la petición no se realiza en nombre de ningún usuario.

Pseudo-autenticación con OAuth El flujo final que nos queda por ver es el de pseudo-autenticación, es decir cuando una web permite autenticar a sus usuarios con las credenciales de un proveedor OAuth. Lo llamamos pseudo-autenticación, porque a diferencia de un sistema de autenticación puro, como puede

Page 19: Entendiendo oAuth

ser OpenID, en el cual se pide la identidad del usuario, en el caso de OAuth se intenta acceder a un recurso protegido en nombre de un usuario y el propio flujo de OAuth hará que el usuario se autentique contra el proveedor de servicios. El cliente en este caso no sabe cuál es la identidad del usuario, pero tiene un token OAuth a través del cual puede acceder a una API y preguntar por su nombre.

Ilustración 2: Autenticación OpenID y pseudo-autenticación OAuth (fuente: Wikipedia)

Míralo de este modo: Si yo quiero saber quién eres tú, tengo dos modos de hacerlo:

1. Pedirte que me muestres un documento que te autentique. Por supuesto ambos debemos acordar que tipos de documentos son válidos para autenticarte (el DNI es válido pero la tarjeta de la biblioteca, no).

2. Pedirte las llaves de tu casa, entrar en ella contigo, abrir tu cartera y mirar tu DNI.

La primera sería una autenticación pura basada en un protocolo como OpenID. La segunda sería pseudo-autenticación basada en OAuth. En el ejemplo del segundo punto, he puesto contigo adrede, para que quede claro de que no puedo hacer lo que quiera cuando esté en tu casa: tan solo puedo hacer lo que tú me hayas autorizado a hacer.

Realmente este flujo es idéntico a cualquiera de los tres flujos anteriores que hemos visto. Todos los pasos son idénticos y la experiencia del usuario es la misma. La única diferencia está en el cliente: antes el cliente solo quiere realizar una llamada a un servicio, mientras que ahora si la llamada OAuth es exitosa, el cliente autentica al usuario dentro de su propio sistema. De esta manera el usuario obtiene acceso a una determinada aplicación web usando sus

Page 20: Entendiendo oAuth

credenciales de otro proveedor OAuth (como pueda ser Facebook o Twitter). Para desarrolladores de aplicaciones es muy interesante, porque no solo evitan que el usuario deba darse de alta en su sistema, si no que además tienen acceso a los datos que el proveedor de OAuth exponga de ellos (p.ej. podrían acceder al perfil de Facebook).