Desde hace un año más o menos hasta hoy, noviembre de 2018, me he visto involucrado en el desarrollo de múltiples APIs y microservicios, todos ellos debidamente protegidos con un API KEY o un token. Pero tengo un pequeño problema: siempre que me pongo con uno nuevo nunca me acuerdo cuál es la forma más sencilla y segura de generar en Python un secreto, una cadena aleatoria en hexadecimal o un API KEY. Es por ello que he decidido crear este POST que, aunque sea corto, hará que tenga un sitio rápido al que volver la próxima vez que tenga una tarea similar. Espero que a ti también te sirva de ayuda.
La forma más sencilla de generar un API KEY en Python (< 3.6)
Antes de Python 3.6, para generar una cadena aleatoria en hexadecimal para utilizar como API KEY, nos podíamos ayudar de los módulos «os» y «binascii».
Por ejemplo, para generar una cadena de longitud 40, solo tenemos que ejecutar las siguientes líneas de código:
>>> import os, binascii >>> binascii.b2a_hex(os.urandom(20)) b'b6026f861fd41a94c3389d54293de9d04bde6f7c'
Descubriendo el módulo secrets en Python (3.6+)
La llegada de Python 3.6 trajo consigo la aparición del módulo secrets
. Según su propia documentación, se indica que:
«El módulo secrets se utiliza para generar números aleatorios criptográficamente fuertes, adecuados para administrar datos como contraseñas, autenticación de usuarios, tokens de seguridad y secretos relacionados»
«En particular, secrets debe ser usado preferentemente frente a la generación de números pseudoaleatorios empleando el módulo random, que está diseñado para el modelado y la simulación, no para la seguridad o la criptografía»
Para simular con el módulo secrets el ejemplo visto en el apartado anterior, basta ejecutar el siguiente código:
>>> import secrets >>> secrets.token_hex(20) 'ccaf5c9a22e854856d0c5b1b96c81e851bafb288'
En ciertas ocasiones, puede que queramos que el secreto forma parte de una URL, por ejemplo, para resetear un password. En ese caso es más apropiado usar la función token_urlsafe
del mismo modo. Esta nos garantiza que los caracteres generados son seguros de usar en una URL:
>>>secrets.token_urlsafe(20) 'dxM4-BL1CPeHYIMmXNQevdlsvhI'
Hay que tener en cuenta que el número que se pasa entre paréntesis no es la longitud del número de caractéres, si no de bytes. En el caso de la función token_hex, 1 byte se corresponden con 2 dígitos hexadecimales. En cuanto a la función token_urlsafe, la cadena devuelta está codificada en Base 64, lo que viene a ser 1,3 caractéres por cada byte (aunque no siempre es así).
Si no se indica el número de bytes a utilizar, el módulo secrets usará uno razonable por defecto (que puede cambiar en cualquier momento en futuras actualizaciones).