¿Cómo generar una cadena impredecible pero corta? [cerrado]

1

Quiero crear algunas URL cortas para los archivos y enlaces cargados en mi propio servidor. Bastante simple, subo archivos y mi script me devuelve un enlace. Al acceder, el enlace se traduce al archivo y comienza la descarga. Como es moderno, quiero que mis enlaces sean cortos y no tan parecidos a UUID4, porque son muy largos.

No quiero que alguien intente algunas URL para encontrar un enlace válido. ¿Tal vez debería enviar solo 404 si una IP ya tenía 10 URL incorrectas?

Para crear cadenas aleatorias cortas, estoy pensando en lo siguiente:

  1. Rellene previamente una tabla SQL (key, target) donde key distingue entre mayúsculas y minúsculas con todos los valores posibles en un rango definido como [a-zA-Z0-9_-~=]{12} . Luego seleccione con WHERE target IS NULL ORDER BY RANDOM() una tecla vacía y úsela. Esto garantizará que nunca genere la misma clave dos veces, pero necesita mucho almacenamiento y puede ser demasiado.
  2. Genero una cadena UUID4 y lanzo un algoritmo hash como SHA3 sobre ella y uso los primeros 12 caracteres del resultado. Entonces trato de insertar esto en mi mesa. Si esto falla, necesito generar un nuevo UUID4 y así sucesivamente ...

Por supuesto, estos son pensamientos muy teóricos, porque creo que estaré bien con 1000 teclas por año. Pero, ¿cómo acortar los servicios de url hacer esto? ¿O no les importa lo "impredecible"?

    
pregunta tjati 10.07.2014 - 11:25
fuente

2 respuestas

4

Si desea impredecible , entonces necesita impredecible . Si comienzas con un UUID y luego juegas con funciones hash, no obtienes valores impredecibles; solo obtienes valores que "parecen aleatorios".

Así que solo use un PRNG criptográficamente seguro . Esto significa /dev/urandom (o algo similar, por ejemplo, java.security.SecureRandom si está desarrollando en Java).

Este comando simple (funciona en cualquier sistema Linux) genera valores de 12 caracteres aleatorios e impredecibles:

dd if=/dev/urandom bs=9 count=1 2>/dev/null | base64 | tr '+/' '_-'

Los caracteres utilizados consisten en letras (mayúsculas y minúsculas), dígitos, '_' y '-'. Por lo tanto, deben encajar muy bien en la URL ( Base64 sin formato produce los signos '+' y '/', que pueden ser problemáticos, pero lo arreglé con la llamada tr ). La entropía es de 72 bits, lo que significa que las cadenas forman parte de un espacio de tamaño 2 72 . Si generas 1000 cadenas, entonces la probabilidad de golpear una de las cadenas es 1000/2 72 , es decir, alrededor de 1 en 4.7 billones de billones (por lo que es mejor que el atacante sea súper afortunado).

La traducción a cualquier marco de programación particular se deja como un ejercicio. El punto realmente importante es usar un PRNG fuerte, no las cosas que simplemente se pretende que sean "estadísticamente aleatorias" como el RANDOM() de SQL o UUID. Esto es seguridad: queremos la aleatoriedad criptográfica , no la aleatoriedad estadística , porque debemos derrotar a un atacante inteligente .

    
respondido por el Tom Leek 10.07.2014 - 16:19
fuente
2

Iría por algún valor de contador y le añadiría algo de aleatoriedad y no almacenaría todos los resultados individuales. Almacenar todos los resultados suena muy complicado. Si utiliza un contador de 4 bytes y lo combina con un valor generado aleatoriamente de 4 bytes, base32 codifica el resultado. Con un contador de 4 bytes puede generar 4294967296 enlaces y el 4 bytes de aleatoriedad debería ser suficiente para evitar que alguien pueda adivinarlo fácilmente. Si necesita generar más enlaces, use más bytes, si necesita más aleatoriedad, use más bytes al azar. Usando un contador, solo necesitas almacenar un solo valor. En lugar de usar un contador, también puede usar la hora actual en milisegundos. Esto es aún más fácil y la posibilidad de generar la misma URL cuando se generan varias URL en poco tiempo es muy pequeña, ya que siempre tiene el valor aleatorio.

    
respondido por el martijnbrinkers 10.07.2014 - 13:00
fuente

Lea otras preguntas en las etiquetas