Algoritmo
Para generar una cadena aleatoria, concatene caracteres dibujados aleatoriamente del conjunto de símbolos aceptables hasta que la cadena alcance la longitud deseada.
Implementación
Aquí hay un código bastante simple y muy flexible para generar identificadores aleatorios. Lea la información que sigue para obtener notas importantes sobre la aplicación.
public class RandomString {
/**
* Generate a random string.
*/
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String lower = upper.toLowerCase(Locale.ROOT);
public static final String digits = "0123456789";
public static final String alphanum = upper + lower + digits;
private final Random random;
private final char[] symbols;
private final char[] buf;
public RandomString(int length, Random random, String symbols) {
if (length < 1) throw new IllegalArgumentException();
if (symbols.length() < 2) throw new IllegalArgumentException();
this.random = Objects.requireNonNull(random);
this.symbols = symbols.toCharArray();
this.buf = new char[length];
}
/**
* Create an alphanumeric string generator.
*/
public RandomString(int length, Random random) {
this(length, random, alphanum);
}
/**
* Create an alphanumeric strings from a secure generator.
*/
public RandomString(int length) {
this(length, new SecureRandom());
}
/**
* Create session identifiers.
*/
public RandomString() {
this(21);
}
}
Ejemplos de uso
Cree un generador inseguro para identificadores de 8 caracteres:
RandomString gen = new RandomString(8, ThreadLocalRandom.current());
Cree un generador seguro para identificadores de sesión:
RandomString session = new RandomString();
Cree un generador con códigos fáciles de leer para imprimir. Las cadenas son más largas que las cadenas alfanuméricas completas para compensar el uso de menos símbolos:
String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);
Usar como identificadores de sesión
Generar identificadores de sesión que probablemente sean únicos no es lo suficientemente bueno, o simplemente podría usar un contador simple. Los atacantes secuestran sesiones cuando se usan identificadores predecibles.
Hay tensión entre longitud y seguridad. Los identificadores más cortos son más fáciles de adivinar, porque hay menos posibilidades. Pero los identificadores más largos consumen más almacenamiento y ancho de banda. Un conjunto más grande de símbolos ayuda, pero puede causar problemas de codificación si los identificadores se incluyen en las URL o se vuelven a ingresar a mano.
La fuente subyacente de aleatoriedad, o entropía, para los identificadores de sesión debe provenir de un generador de números aleatorios diseñado para la criptografía. Sin embargo, la inicialización de estos generadores a veces puede ser computacionalmente costosa o lenta, por lo que se debe hacer un esfuerzo para reutilizarlos cuando sea posible.
Usar como identificadores de objeto
No todas las aplicaciones requieren seguridad. La asignación aleatoria puede ser una forma eficiente para que múltiples entidades generen identificadores en un espacio compartido sin ninguna coordinación o partición. La coordinación puede ser lenta, especialmente en un entorno agrupado o distribuido, y dividir un espacio causa problemas cuando las entidades terminan con recursos compartidos que son demasiado pequeños o demasiado grandes.
Los identificadores generados sin tomar medidas para hacerlos impredecibles deben protegerse por otros medios si un atacante puede verlos y manipularlos, como sucede en la mayoría de las aplicaciones web. Debe haber un sistema de autorización separado que proteja los objetos cuyo identificador pueda ser adivinado por un atacante sin permiso de acceso.
También se debe tener cuidado al usar identificadores que sean lo suficientemente largos como para hacer improbables las colisiones dado el número total anticipado de identificadores. Esto se conoce como "la paradoja del cumpleaños". La probabilidad de una colisión, p , es aproximadamente n 2 / (2q x ), donde n es el número de identificadores realmente generados, q es el número de símbolos distintos en el alfabeto yx es la longitud de los identificadores. Debe ser un número muy pequeño, como 2 a 50 o menos.
Resolver esto muestra que la posibilidad de colisión entre 500k identificadores de 15 caracteres es de 2 a 52 , lo que probablemente es menos probable que los errores no detectados de los rayos cósmicos, etc.
Comparación con UUID
Según su especificación, los UUID no están diseñados para ser impredecibles y no deben usarse como identificadores de sesión.
Los UUID en su formato estándar ocupan mucho espacio: 36 caracteres para solo 122 bits de entropía. (No todos los bits de un UUID "aleatorio" se seleccionan aleatoriamente). Una cadena alfanumérica elegida aleatoriamente contiene más entropía en solo 21 caracteres.
Los UUID no son flexibles; Tienen una estructura y diseño estandarizados. Esta es su principal virtud, así como su principal debilidad. Al colaborar con una parte externa, la estandarización ofrecida por UUID puede ser útil. Para uso puramente interno, pueden ser ineficientes.