13 septiembre 2010

Destripando OAuth en Twitter

Avisados estábamos de que a partir del 1 de Septiembre en Twitter se dejaba de permitir la autenticación básica en sus aplicaciones. A partir de ese momento, a todos aquellos que éramos amiguitos de desarrollar scripts en perl o python por ejemplo para comunicarse con Twitter, nos surgió una traba nueva, o como se ha denominado en Internet: el OAuthcalipsis. Así pues, la versión anterior de Tweetme.pl, herramienta de la que os hablamos hace tiempo, también dejó de funcionar!

Anteriormente, con proveer un par usuario/contraseña de una cuenta válida de Twitter, en el desarrollo y la ejecución, todo era maravilloso de sencillo, aunque más inseguro, puesto que los ingredientes de la receta de la autenticación viajaban en claro (cuántas y cuántas veces habremos dejado de utilizar twitter en eventos con redes compartidas/peligrosas) a través de la red.

OAuth llega a solucionarle a Twitter este problema… y a generarnos otros tantos a los desarrolladores "amateur". Me explicaré un poco mejor. Para la autenticación mediante OAuth, es necesario proveer 4 elementos a Twitter:
  • Consumer Key -> El desarrollador ha de registrar, a nombre de una cuenta twitter, la aplicación que desee. Así se generará este identificador único de aplicación.
  • Consumer Secret -> Para evitar suplantar diferentes identificadores de aplicación (mediante un ataque de fuerza bruta, pero que muy muy bruta, 21 caracteres alfanuméricos con mayúsculas y minúsuculas), se complementa el par con una clave denominada Consumer Secret.
  • Access Token Key -> Para cada usuario, será necesario asociar un identificativo de token que permita suplantar para esa aplicación, a ese usuario mediante ese token para operar en Twitter (de hecho es posible definir la aplicación como de "sólo lectura" o "lectura/escritura" según las necesidades)
  • Access Secret -> Como par asociado al Token Key se establece un Token secret.
De esta manera, cuando un usuario requiera la utilización de una aplicación/script que use Twitter, será necesario proveer los cuatro elementos descritos.

Si somos los desarrolladores de la aplicación/script y sólo lo vamos a utilizar nosotros, no hay problema en obtener esos cuatro datos directamente y "hardcodearlo" en el código. El problema viene en el momento en el que se comparte/distribuye esa aplicación a terceros, ya sea como software libre o como software comercial.

Y es que resulta que Twitter no ve con buenos ojos el distribuir el consumer key y consumer secret de una aplicación determinada, de forma masiva. Twitter comunicó que, una vez que un par consumer key/secret son de dominio público, las revocarían (en su propia Revocation List) y la aplicación queda inutilizada.

Por otra parte, el par Access Token Key/secret es único para cada usuario que quiera hacer uso de esa aplicación. En el caso que N usuarios quieran utilizar una aplicación twitter con OAuth, deberán permitir a su usuario twitter que la aplicación identificada por $consumer_key y $consumer_secret lea/escriba en twitter con su identidad.

Para ello es necesario generar un par de Token key/secret distintos para cada cuenta, manteniéndose fijo el par Consumer key/secret que identifican a la aplicación. Para generar los access token key/secret es necesario haber hecho login vía web en Twitter con la cuenta que queramos y, al ejecutar la aplicación, ésta nos deberá proveer de una URL a la que acceder, que nos indicará que la aplicación X requiere nuestra aprobación para ser usada con nuestra cuenta. Después de aceptar, aparecerá un PIN que habrá que introducir en la aplicación para poder obtener el par token key/secret también necesarios para la aplicación.

Algunos lectores diréis: "No me cuadra esto que dicen en SbD porque yo no he actualizado mi cliente Twitter (como Tweetdeck por ejemplo) y todo me sigue funcionando igual y sin problemas. Además no he tenido que hacer cosas raras con los tokens y los consumer keys ni nada de esto". Pues efectivamente, tenéis razón. Y es que es posible, para algunas aplicaciones, utilizar xAuth, otra forma de autenticación que requiere que Twitter manualmente verifique y apruebe ese tipo de autenticación para dicha aplicación en concreto. Me recuerda un poco al procedimiento para añadir una aplicación en la appstore de Apple. Para ello hay que proporcionar, entre otras cosas el "consumer key" de la aplicación, pero que en el fondo son peticiones con POST vía HTTPS a Twitter.

En aplicaciones no "reconocidas" por Twitter o FOSS, aún no se ha solucionado el problema de la distribución del consumer key/secret en formato texto. Debido al concepto Open Source y al tener que poner a disposición de cualquiera el código fuente completo de la aplicación, y que si Twitter descubre un par consumer key/secret éstas serán deshabilitadas, me gustaría proponer un par de opciones, que por supuesto no son la panacea, puesto que son fácilmente bypasseables, pero al menos Twitter no podrá invalidar el par consumer key/secret porque no van en la propia aplicación en modo texto:

  • Ofuscar tanto el valor como el nombre del parámetro a la autenticación con OAuth mediante un ROT13 o cualquier otro mecanismo de cifrado. (Método propuesto por Marc Mims, mantenedor del módulo Net::Twitter para Perl)
De esta manera:

Net::Twitter->new(
   traits => [qw/API::REST OAuth RetryOnError/],
   decode_entities => 1,
   (   
    grep tr/a-zA-Z/n-za-mN-ZA-M/, map $_,
    pbafhzre_xrl => 'ZlPbafhzreXrl',
    pbahfzre_frperg => 'ZlFrperg',
   ),
);


En tiempo de ejecución se sustituye por:

Net::Twitter->new(
    traits => [qw/API::REST OAuth RetryOnError/],
    decode_entities => 1,
    consumer_key => 'MyConsumerKey',
    consumer_secret => 'MySecret',
);

Lo cual no es publicarlos en claro en el código.

  • Otra opción sería forzar que los valores de ambas variables estén en una ubicación remota. Puesto que para acceder a Twitter, es necesario que haya conectividad con Internet, antes de acceder a la autenticación, es obtener consumer_key y consumer_secret previamente y utilizarlos en la autenticación. Si Twitter bloquea dicho par, con generar uno nuevo, no es necesario bajar una nueva versión de la aplicación y "hardcodearlos" (que puede generar retrasos de semanas si nos referimos a una aplicación que esté en la AppStore de Apple por ejemplo) sino hacer un cambio en el servidor únicamente.

Para Tweetme.pl he implementado una mezcla de ambas, que no incumpla las exigencias de Twitter, pero que permita no tener que entregar un programa compilado y ofuscado (que finalmente sería comprometido igualmente por gente con capacidades de reversing), ni que utilice xAuth, por el papeleo y trámite que ello permite con Twitter (siempre y cuando aprueben xAuth en una aplicación Open Source, claro está). Además, en esta nueva versión se provee de un script para que sea sencillo obtener los tokens y personalizarlo para cada usuario.

5 comments :

a0rtega dijo...

Un post de 10 :)

Se me viene a la cabeza otra solución. Se podría montar un intermediario entre el cliente final y Twitter, que esté funcionando en una máquina administrada por el desarrollador. Esta aplicación será la encargada del manejo de claves (consumer), y de enviar las peticiones que mande el cliente final a Twitter.

cliente final <-> intermediario <-> Twitter

El cliente final solo se encargaría de la interacción que quiere realizar con Twitter (incluidos token access), y mandaría las peticiones al intermediario. El intermediario maneja todas las claves, y envía la petición final a Twitter.

Habría que montar un pequeño protocolo entre cliente final e intermediario.

De esta forma las claves de la aplicación (consumer) no pueden verlas los que descarguen el cliente final, y por otro lado el desarrollador maneja las claves sin necesidad de realizar actualizaciones (en caso de que haya sido comprometida de alguna forma).
Por otro lado, el código de toda la infraestructura podría seguir siendo libre, salvo las claves que utilice el intermediario.

Quizás esto ha sido pensado ya antes y se ha descartado por algún motivo, pero yo creo que en un principio el mecanismo es factible y seguro (aunque algo más costoso).

Un saludo! :)

vierito5 dijo...

Muy buen post y menuda liada parda por parte de twitter.

Iñaki R. dijo...

Yo he hecho algo parecido a lo que comentaba a0rtega para algún proyecto personal usando xml-rpc. En perl son apenas 5 líneas de código y funciona bastante bien.

Saludos

Anónimo dijo...

De todo esto lo unico que queda claro es que mucho del auge de twitter se vera afectado por lo menos mientras aya una solucion mucho mas generalizada para los desarrolladores de open sorce.

Mientras seguiremos con scripts caseros para evitar este problema.

Anónimo dijo...

a0rtega, ¿no podría ser un problema que el tráfico de tu servidor intermediario comenzara a crecer debido al éxito de tu script? :-)