2008-09-10 35 views
12

Estoy buscando una forma, específicamente en PHP, de que se garantice que siempre obtenga una clave única.Generación de clave única

he hecho lo siguiente:

strtolower(substr(crypt(time()), 0, 7)); 

Pero he encontrado que de vez en cuando termino con una clave duplicada (rara vez, pero con la suficiente frecuencia).

También he pensado en hacer:

strtolower(substr(crypt(uniqid(rand(), true)), 0, 7)); 

embargo, según el sitio web de PHP, uniqid() podría, si uniqid() se llama dos veces en el mismo microsegundo, que podría generar la misma clave. Estoy pensando que la adición de rand() raramente lo haría, pero aún es posible.

Después de las líneas mencionadas anteriormente también elimino caracteres como L y O por lo que es menos confuso para el usuario. Esto quizás sea parte de la causa de los duplicados, pero sigue siendo necesario.

Una opción que tengo en mente es crear un sitio web que generará la clave, almacenándola en una base de datos, asegurando que sea completamente única.

¿Alguna otra idea? ¿Hay sitios web que ya hacen esto que tienen algún tipo de API o simplemente devuelven la clave? Encontré http://userident.com pero no estoy seguro de si las claves serán completamente únicas.

Esto debe ejecutarse en segundo plano sin ninguna intervención del usuario.

+0

¿Por qué las contraseñas deben ser completamente únicas? –

+0

Supongo que crypt es solo porque necesita criptar valor, no tiene nada que ver con la creación de valor único, ¿o no? –

+0

Vea también: [Función PHP para generar v4 UUID] (http://stackoverflow.com/a/15875555/1338292). –

Respuesta

19

Sólo hay 3 formas de generar valores únicos, en lugar de que sea contraseñas, nombres de usuario, etc .:

  1. utilizar un generador eficaz GUID - estos son largas y no se pueden reducir. Si solo usa la pieza , NO FALLA.
  2. Al menos parte del número se genera secuencialmente fuera de una secuencia única. Puede agregar fluff o codificación para que parezca menos secuencial. La ventaja es que comienzan en corto, la desventaja es que requieren una sola fuente. La solución para la limitación de fuente única es tener fuentes numeradas, por lo que debe incluir [fuente #] + [seq #] y luego cada fuente puede generar su propia secuencia.
  3. Generarlos a través de otros medios y luego compararlos con el único historial de valores generados previamente.

Cualquier otro método no está garantizado. Tenga en cuenta que, fundamentalmente, está generando un número binario (es una computadora), pero luego puede codificarlo en hexadecimal, decimal, base64 o en una lista de palabras. Elija una codificación que se ajuste a su uso. Por lo general, para los datos ingresados ​​por el usuario, usted desea alguna variación de Base32 (que usted insinuó).

Nota sobre GUIDS: Ganan su fuerza de singularidad a partir de su longitud y el método utilizado para generarlos. Cualquier cosa inferior a 128 bits no es segura. Más allá de la generación de números aleatorios, hay características que entran en un GUID para hacerlo más único. Tenga en cuenta que solo son prácticamente únicos, no completamente únicos. Es posible, aunque es prácticamente imposible tener un duplicado.

Actualizado Nota sobre GUIDS: Después de haber escrito esto aprendí que muchos generadores GUID utilizan un generador de números aleatorios criptográficamente seguro (difíciles o imposibles de predecir el siguiente número generado, y una no es probable que repita). En realidad hay 5 diferentes UUID algorithms. Algoritmo 4 es lo que Microsoft usa actualmente para la API de generación de GUID de Windows. A GUID es la implementación de Microsoft del estándar UUID.

actualización: Si desea 7 a 16 caracteres, entonces tienes que utilizar cualquiera de los métodos 2 ó 3.

En pocas palabras: Francamente no hay tal cosa como totalmente único. Incluso si fuera con un generador secuencial eventualmente se quedaría sin almacenamiento usando todos los átomos del universo, volviendo a conectarse consigo mismo y repitiendo. Tu única esperanza sería la muerte térmica del universo antes de llegar a ese punto.

Incluso el mejor generador de números aleatorios tiene la posibilidad de repetirse igual al tamaño total del número aleatorio que está generando. Tome un cuarto por ejemplo. Es un generador de bits completamente aleatorio, y sus probabilidades de repetir son 1 en 2.

Así que todo se reduce a su umbral de exclusividad. Puede tener un 100% de exclusividad en 8 dígitos para 1,099,511,627,776 números usando una secuencia y luego base32 codificándolo. Cualquier otro método que no implique verificar contra una lista de números pasados ​​solo tiene probabilidades equivalentes a n/1,099,511,627,776 (donde n = número de números previos generados) de no ser únicos.

+0

Hola, ¿tiene alguna otra lectura sobre el número 2, me gustaría utilizar este tipo de generación de código utilizando diferentes "fuentes", Gracias. – Jon

+0

@Jon: No tengo ninguna lectura sobre esto, pero esencialmente concatena el identificador de fuente con una secuencia de esa fuente. Entonces sabes que es único. Por ejemplo, si tuviera dos fuentes, entonces tendría una secuencia de A1, A2, A3, A4 ... A999 y otra secuencia de B1, B2, B3, B4. .. B999. Dado que una identificación de la fuente A nunca comenzará con B, entonces usted sabe que nunca habrá una colisión. –

+0

k gracias, ¿podría el identificador de origen ser una identificación para una tabla db para que cuando se ingresa un código la información se pueda recopilar de un registro en una tabla? – Jon

0

Sin necesidad de escribir el código, mi lógica sería:

generar una cadena aleatoria de caracteres aceptables lo que te gusta.
Luego agregue la mitad de la marca de fecha (segundos parciales y todo) al frente y la otra mitad al final (o en el medio, si lo prefiere).

Stay JOLLY!
H

+1

Esto está cerca, pero dependiendo de su rutina aleatoria solo tiene un poco más de microsegundos de precisión. Como él mencionó, uniqid falló por la misma posibilidad. –

0

Si utiliza su método original, pero agrega el nombre de usuario o emailaddress delante de la contraseña, siempre será único si cada usuario solo puede tener 1 contraseña.

0

Puede que le interese este artículo sobre el mismo problema: GUIDs are globally unique, but substrings of GUIDs aren't.

El objetivo de este algoritmo es el uso de la combinación de tiempo y ubicación ("coordenadas espacio-temporales" para los frikis de la relatividad por ahí) como la clave de unicidad. Sin embargo, el cronometraje no es perfecto, por lo que existe la posibilidad de que, por ejemplo, se generen dos GUID en rápida sucesión desde la misma máquina, muy cerca el uno del otro a tiempo de que la marca de tiempo sea la misma. Ahí es donde entra en juego la uniquifier

0

que suele hacer de esta manera:.

$this->password = ''; 

for($i=0; $i<10; $i++) 
{ 
    if($i%2 == 0) 
     $this->password .= chr(rand(65,90)); 
    if($i%3 == 0) 
     $this->password .= chr(rand(97,122)); 
    if($i%4 == 0) 
     $this->password .= chr(rand(48,57)); 
} 

supongo que hay algunos agujeros teóricos, pero nunca he tenido un problema con la duplicación. Normalmente lo uso para contraseñas temporales (como después de restablecer una contraseña) y funciona lo suficientemente bien para eso.

-1

Suelo hacer una subcadena aleatoria (aleatorizar cuántos caracteres entre 8 y 32, o menos para comodidad del usuario) o el MD5 de algún valor que he obtenido, o la hora, o alguna combinación. Para obtener más aleatoriedad, hago MD5 del valor de vencimiento (por ejemplo, apellido) concatenar con el tiempo, MD5 de nuevo, luego tomar la subcadena aleatoria. Sí, usted podría obtener contraseñas iguales, pero no es muy probable en absoluto.

+0

Si toma una subcadena de un hash criptográficamente seguro, vence la singularidad del hash. Ninguna porción de un hash es más segura o aleatoria que cualquier otra. Es igual de probable obtener contraseñas iguales como el uso de una llamada regular a un generador de números aleatorios. –

0

Puede que le interese la implementación segura de Steve Gibson de un generador de contraseñas (sin fuente, pero tiene una descripción detallada de cómo funciona) en https://www.grc.com/passwords.htm.

El sitio crea enormes contraseñas de 64 caracteres, pero, ya que son completamente al azar, que podría fácilmente dar los primeros caracteres de 8 (o muchos) sin embargo para un menos seguro, pero "tan aleatorio como sea posible" contraseña.

EDIT: desde sus respuestas posteriores veo que necesita algo más parecido a un GUID que una contraseña, por lo que probablemente no es lo que quiere ...

1

Cualquier algoritmo dará lugar a duplicados.

Por lo tanto, ¿podría sugerirle que use su algoritmo * existente y simplemente verifique si hay duplicados?

* Ligera adición: Si uniqid() puede ser no único en función del tiempo, también incluye un contador global que se incrementa después de cada invocación. De esa forma, algo es diferente incluso en el mismo microsegundo.

+0

GUID (o UUIDS) y las secuencias son las únicas dos formas de evitar duplicados, pero usted es correcto para todos los demás algoritmos mencionados aquí. –

+0

Si se permiten longitudes de identificador arbitrarias, estoy de acuerdo. Si quiere mantener 8 caracteres como en sus ejemplos, simplemente no es suficiente. –

+0

8 caracteres es suficiente para exactamente 1.099.511.627.776 contraseñas únicas si utiliza Base32, que es respetable para los datos ingresados ​​manualmente (32^8) Esto no permite la verificación, ni excluye patrones como 00000000. –

0

Como comentó Frank Kreuger, vaya con un generador de GUID.

Como this one

0

todavía no estoy viendo qué las contraseñas tienen que ser únicos? ¿Cuál es la desventaja si 2 de tus usuarios tienen la misma contraseña?

Esto supone que estamos hablando de contraseñas atadas a ID de usuario, y no solo identificadores únicos. Si es lo que está buscando, ¿por qué no usar GUID?

+0

porque puede no ser siempre una contraseña, sino su nombre de usuario/identificación de acceso o decir una identificación de transacción. Ambos son básicamente un nombre de usuario, así que tienen que ser únicos. Tengo la configuración de la base de datos para aceptar contraseñas únicas , pero de nuevo, no puedo asumir que estoy tratando con un dat a que tengo acceso. La otra cosa es que solo quiero 7 a tal vez 15 caracteres. Los GUID suelen ser mucho más largos y, por lo tanto, terminarán siendo únicos con bastante facilidad. –

0

creo que la parte de su problema es que usted está tratando de una función singular para dos usos separados ... contraseñas y TRANSACTION_ID

estos realmente son dos áreas problemáticas diferentes y en realidad no es la mejor manera de trata de abordarlos juntos.

0

recientemente que quería una clave única aleatoria rápida y sencilla, así que hice lo siguiente:

$ukey = dechex(time()) . crypt(time() . md5(microtime() + mt_rand(0, 100000))); 

Así que, básicamente, me sale el Tiempo Unix en segundos y agregar una cadena MD5 aleatorio generado de vez + número al azar . No es lo mejor, pero para solicitudes de baja frecuencia es bastante bueno. Es rápido y funciona.

Hice una prueba en la que generaba miles de claves y luego buscaba repeticiones, y teniendo alrededor de 800 teclas por segundo no había repeticiones, así que no estaba mal. Supongo que depende totalmente de mt_rand()

Lo uso para un rastreador de encuestas donde obtenemos una tasa de envío de aproximadamente 1000 encuestas por minuto ... así que por ahora (cruza los dedos) no hay duplicados. Por supuesto, la tasa no es constante (obtenemos los envíos en ciertos momentos del día) así que esto no es a prueba de fallas ni la mejor solución ... la sugerencia es usar un valor incremental como parte de la clave (en mi caso, Usé el tiempo(), pero podría ser mejor).

+1

No entiendo por qué necesita los valores de md5. MD5 es un algoritmo unidireccional que crea una firma. Tenga cuidado de que los diferentes valores de entrada puedan dar como resultado la creación de la misma firma, las funciones de MD5 se disparan para intentar devolver resultados diferentes cuando los valores de entrada son ligeramente diferentes y no completamente diferentes. Entonces, al agregar MD5, creo que aumenta la probabilidad de obtener valores duplicados. –

0

ingoring la parte crypting que no tiene mucho que ver con la creación de un valor único que suelen utilizar éste:

function GetUniqueValue() 
{ 
    static $counter = 0; //initalized only 1st time function is called 
    return strtr(microtime(), array('.' => '', ' ' => '')) . $counter++; 
} 

Cuando se llama en un mismo proceso $ contador se incrementa por lo que el valor es siempre único en el mismo proceso .

Cuando se invoca en diferentes procesos debe ser realmente desafortunado para obtener 2 llamadas microtime() con los mismos valores, piense que las llamadas microtime() también tienen valores diferentes cuando se llaman en el mismo script.

Cuestiones relacionadas