Pregunta

Estoy buscando una manera, específicamente en PHP, de garantizar que siempre obtendré una clave única.

He hecho lo siguiente:

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

Pero descubrí que de vez en cuando termino con una clave duplicada (rara vez, pero con bastante frecuencia).

También he pensado en hacer:

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

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

Después de las líneas mencionadas anteriormente, también elimino caracteres como L y O para que sea menos confuso para el usuario.Esto puede ser parte de la causa de los duplicados, pero aún así es necesario.

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

¿Alguna otra idea?¿Existe algún sitio web que ya haga esto y que tenga algún tipo de API o simplemente devuelva la clave?encontré http://identificadordeusuario.com pero no estoy seguro de si las claves serán completamente únicas.

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

¿Fue útil?

Solución

Solo hay 3 formas de generar valores únicos, más bien contraseñas, ID de usuario, etc.:

  1. Utilice un generador de GUID eficaz: son largos y no se pueden reducir.Si solo usas parte fallaste.
  2. Al menos parte del número se genera secuencialmente a partir de una única secuencia.Puede agregar tonterías o codificación para que parezca menos secuencial.La ventaja es que empiezan poco a poco; la desventaja es que requieren una única fuente.La solución para la limitación de una sola fuente es tener fuentes numeradas, por lo que incluye [n.° de fuente] + [n.° de secuencia] y luego cada fuente puede generar su propia secuencia.
  3. Generarlos a través de otros medios y luego compararlos con el historial único de valores generados previamente.

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

Nota sobre GUIDAS:Obtienen su fuerza de singularidad a partir de su longitud y del método utilizado para generarlos. Cualquier valor inferior a 128 bits no es seguro. Más allá de la generación de números aleatorios, hay características que se incluyen en un GUID para hacerlo más exclusivo.Tenga en cuenta que son prácticamente únicos, no completamente únicos.Es posible, aunque prácticamente imposible, tener un duplicado.

Nota actualizada sobre GUIDS:Desde que escribí esto, aprendí que muchos generadores de GUID utilizan un generador de números aleatorios criptográficamente seguro (difícil o imposible predecir el siguiente número generado y no es probable que se repita).En realidad hay 5 diferentes Algoritmos UUID.El algoritmo 4 es lo que Microsoft utiliza actualmente para la API de generación de GUID de Windows.A GUID es la implementación de Microsoft del estándar UUID.

Actualizar:Si desea de 7 a 16 caracteres, deberá utilizar el método 2 o 3.

Línea de fondo:Francamente, no existe algo completamente único.Incluso si usaras un generador secuencial, eventualmente te quedarías sin almacenamiento usando todos los átomos del universo, volviendo así a ti mismo y repitiendo.Su ú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 repetir un tamaño igual al tamaño total del número aleatorio que estás generando.Tomemos una moneda de veinticinco centavos, por ejemplo.Es un generador de bits completamente aleatorio y sus probabilidades de repetirse son de 1 en 2.

Así que todo se reduce a tu umbral de unicidad.Puede tener 100% de unicidad en 8 dígitos para 1,099,511,627,776 números usando una secuencia y luego codificándola en base32.Cualquier otro método que no implique comparar con una lista de números anteriores solo tiene probabilidades iguales a n/1,099,511,627,776 (donde n=número de números anteriores generados) de no ser único.

Otros consejos

Cualquier algoritmo dará como resultado duplicados..

Por lo tanto, ¿podría sugerirle que utilice su algoritmo existente* y simplemente busque duplicados?

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

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

Genere una cadena aleatoria a partir de los caracteres aceptables que desee.
Luego agregue la mitad del sello de fecha (segundos parciales y todo) al frente y la otra mitad al final (o en algún lugar en el medio si lo prefiere).

¡Mantente ALEGRE!
h

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

Quizás te interese este artículo que trata el mismo tema: Los GUID son únicos a nivel mundial, pero las subcadenas de GUID no lo son.

El objetivo de este algoritmo es utilizar la combinación de tiempo y ubicación ("coordenadas espacio-temporales" para los fanáticos de la relatividad) como 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, tan cerca uno del otro en el tiempo que la marca de tiempo sería la misma.Ahí es donde entra en juego el unicificador.

Normalmente lo hago así:

$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 problemas con la duplicación.Normalmente lo uso para contraseñas temporales (como después de restablecer una contraseña) y funciona bastante bien para eso.

Como comentó Frank Kreuger, opte por un generador GUID.

Como Éste

¿Todavía no entiendo por qué las contraseñas tienen que ser únicas?¿Cuál es la desventaja si 2 de sus usuarios tienen la misma contraseña?

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

Quizás le interese la implementación extremadamente 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/contraseñas.htm.

El sitio crea contraseñas enormes de 64 caracteres pero, dado que son completamente aleatorias, puedes tomar fácilmente los primeros 8 (o la cantidad que sea) para obtener una contraseña menos segura pero "lo más aleatoria posible".

EDITAR:Según tus respuestas posteriores, veo que necesitas algo más parecido a un GUID que a una contraseña, por lo que probablemente esto no sea lo que quieres...

Creo que parte de su problema es que nos está intentando una función singular para dos usos separados...contraseñas y id_transacción

Estas son realmente dos áreas problemáticas diferentes y realmente no es mejor tratar de abordarlas juntas.

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

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

Entonces, básicamente, obtengo el tiempo de Unix en segundos y agrego una cadena md5 aleatoria generada a partir de tiempo + número aleatorio.No es el mejor, pero para solicitudes de baja frecuencia está bastante bien.Es rápido y funciona.

Hice una prueba en la que generaba miles de claves y luego buscaba repeticiones, y teniendo alrededor de 800 claves por segundo no hubo repeticiones, así que no está 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, el ritmo no es constante (recibimos los envíos a determinadas horas del día), por lo que esta no es una solución infalible ni la mejor...el consejo es usar un valor incremental como parte de la clave (en mi caso, usé time(), pero podría ser mejor).

Ingresando a la parte de cifrado que no tiene mucho que ver con la creación de un valor único, normalmente uso este:

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

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

Cuando se llama en diferentes procesos, debe tener mucha mala suerte para obtener 2 llamadas de microtime() con los mismos valores, piense que las llamadas de microtime() generalmente también tienen valores diferentes cuando se llaman en el mismo script.

Por lo general, hago una subcadena aleatoria (aleatoriamente cuántos caracteres están entre 8 y 32, o menos para comodidad del usuario) o el MD5 de algún valor que he ingresado, o el tiempo, o alguna combinación.Para mayor aleatoriedad, hago MD5 del valor venido (digamos apellido), lo concateno con el tiempo, MD5 nuevamente y luego tomo la subcadena aleatoria.Sí tú podría obtenga contraseñas iguales, pero no es muy probable en absoluto.

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