Pregunta

Estoy usando una api que toma un nombre de 21 caracteres como máximo para representar una sesión interna que dura alrededor de dos días. Me gustaría que el nombre no fuera significativo usando algún tipo de hasing? md5 genera 40 caracteres, ¿hay algo más que pueda usar?

Por ahora uso 'userid [: 10]' + hora de creación: ddhhmmss + random 3 chars.

Gracias,

¿Fue útil?

Solución

Si leo tu pregunta correctamente, quieres generar un token de identificación arbitrario que debe tener un máximo de 21 caracteres. ¿Tiene que ser muy resistente a adivinar? El ejemplo que dio no es "fuerte desde el punto de vista" en el sentido de que se puede adivinar buscando bien menos de la mitad de todo el espacio de teclas posible.

No dice si los caracteres pueden ser todos los 256 caracteres ASCII, o si debe limitarse a, por ejemplo, ASCII imprimible (33-127, inclusive), o un rango menor.

Hay un módulo de Python diseñado para UUID s (Universent Unique IDentifiers). Es probable que desee uuid4, que genera un UUID aleatorio y utiliza el soporte del sistema operativo si está disponible (en Linux, Mac, FreeBSD y probablemente otros).

>>> import uuid
>>> u = uuid.uuid4()
>>> u
UUID('d94303e7-1be4-49ef-92f2-472bc4b4286d')
>>> u.bytes
'\xd9C\x03\xe7\x1b\xe4I\xef\x92\xf2G+\xc4\xb4(m'
>>> len(u.bytes)
16
>>> 

16 bytes aleatorios es muy impensable, y no hay necesidad de usar los 21 bytes completos que su API permite, si lo que desea es tener un identificador opaco no supuestable.

Si no puede usar bytes sin procesar de esa manera, lo que probablemente sea una mala idea porque es más difícil de usar en los registros y otros mensajes de depuración y es más difícil de comparar a simple vista, luego convierta los bytes en algo un poco más legible, como utilizando la codificación de base 64, con el resultado reducido a 21 (o lo que sea) bytes:

>>> u.bytes.encode("base64")
'2UMD5xvkSe+S8kcrxLQobQ==\n'
>>> len(u.bytes.encode("base64")) 
25
>>> u.bytes.encode("base64")[:21]
'2UMD5xvkSe+S8kcrxLQob'
>>> 

Esto te da una cadena aleatoria de muy alta calidad de longitud 21.

Puede que no te guste el '+' o '/' que puede estar en una cadena base-64, ya que sin un escape adecuado podría interferir con las URL. Ya que piensas usar "3 caracteres aleatorios", no creo que esto sea una preocupación tuya. Si es así, podría reemplazar esos caracteres con otra cosa ('-' y '.' Podrían funcionar), o eliminarlos si están presentes.

Como han señalado otros, puedes usar .encode (" hex ") y obtener el equivalente hexadecimal, pero eso es solo 4 bits de aleatoriedad / carácter * 21 caracteres máximo te da 84 bits de aleatoriedad en lugar de el doble. Cada bit duplica su espacio clave, haciendo que el espacio de búsqueda teórica sea mucho más pequeño. Por un factor de 2E24 más pequeño.

Su espacio de teclas todavía tiene un tamaño de 2E24, incluso con codificación hexadecimal, por lo que creo que es más una preocupación teórica. No me preocuparía que las personas realicen ataques de fuerza bruta contra tu sistema.

Editar :

P.S .: La función uuid.uuid4 usa libuuid si está disponible. Eso obtiene su entropía de os.urandom (si está disponible) de lo contrario de la hora actual y la dirección MAC de Ethernet local. Si libuuid no está disponible, la función uuid.uuid4 obtiene los bytes directamente de os.urandom (si está disponible), de lo contrario, utiliza el módulo aleatorio. El módulo aleatorio usa una semilla predeterminada basada en os.urandom (si está disponible), de lo contrario un valor basado en la hora actual. El sondeo se realiza para cada llamada de función, por lo que si no tiene os.urandom, la sobrecarga es un poco más grande de lo que podría esperar.

¿Quieres llevar el mensaje a casa? Si sabes que tienes os.urandom entonces podrías hacerlo

os.urandom(16).encode("base64")[:21]

pero si no quiere preocuparse por su disponibilidad, use el módulo uuid.

Otros consejos

La representación hexadecimal de MD5 tiene una aleatoriedad muy pobre: ??solo obtienes 4 bits de entropía por carácter.

Usa caracteres aleatorios, algo como:

import random
import string
"".join([random.choice(string.ascii_letters + string.digits + ".-")
        for i in xrange(21)])

En la opción, coloque todos los caracteres aceptables.

Si usa una función hash real como SHA1, también obtendrá buenos resultados si se usa correctamente , la complejidad agregada y el consumo de CPU no parecen justificados para sus necesidades. Solo quieres una cadena aleatoria.

¿Por qué no tomar los primeros 21 caracteres de hash md5 o SHA1?

El módulo base64 puede hacer codificación de URL segura. Entonces, si es necesario, en lugar de

u.bytes.encode("base64")

que podrías hacer

import base64

token = base64.urlsafe_b64encode(u.bytes)

y, convenientemente, para volver a convertir

u = uuid.UUID(bytes=base64.urlsafe_b64decode(token))

¿Caracteres, o bytes? Si toma cadenas arbitrarias, solo puede usar los bytes y no preocuparse por expandir a caracteres legibles (para los cuales base64 sería mejor que el hexadecimal).

MD5 genera 16 caracteres si no usas la expansión hexadecimal. SHA1 genera 20 bajo la misma condición.

>>> import hashlib
>>> len(hashlib.md5('foobar').digest())
16
>>> len(hashlib.sha1('foobar').digest())
20

Se necesitan pocos bytes adicionales después de eso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top