Cómo generar una cadena alfanumérica aleatoria
He estado buscando un algoritmo Java simple para generar una cadena alfanumérica pseudoaleatoria. En mi situación, se usaría como un identificador de sesión/clave único que "probablemente" sería único a lo largo de 500K+
la generación (mis necesidades realmente no requieren nada mucho más sofisticado).
Idealmente, podría especificar una longitud según mis necesidades de singularidad. Por ejemplo, una cadena generada de longitud 12 podría verse así "AEYGF7K0DM1X"
.
Algoritmo
Para generar una cadena aleatoria, concatene caracteres extraídos aleatoriamente del conjunto de símbolos aceptables hasta que la cadena alcance la longitud deseada.
Implementación
A continuación se muestra 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();
Crea 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 suficiente, o simplemente podría usar un contador simple. Los atacantes secuestran sesiones cuando se utilizan 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 manualmente.
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 criptografía. Sin embargo, la inicialización de estos generadores a veces puede resultar costosa o lenta desde el punto de vista computacional, por lo que se debe hacer un esfuerzo para reutilizarlos cuando sea posible.
Usar como identificadores de objetos
No todas las aplicaciones requieren seguridad. La asignación aleatoria puede ser una forma eficaz para que varias entidades generen identificadores en un espacio compartido sin ninguna coordinación ni 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 demasiado pequeños o demasiado grandes.
Los identificadores generados sin tomar medidas para hacerlos impredecibles deben protegerse por otros medios si un atacante pudiera verlos y manipularlos, como sucede en la mayoría de las aplicaciones web. Debería haber un sistema de autorización independiente que proteja los objetos cuyo identificador pueda ser adivinado por un atacante sin permiso de acceso.
También se debe tener cuidado de utilizar identificadores que sean lo suficientemente largos como para que las colisiones sean improbables dado el número total previsto 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 y x es la longitud de los identificadores. Debe ser un número muy pequeño, como 2‑50 o menos.
Resolver esto muestra que la probabilidad de colisión entre 500.000 identificadores de 15 caracteres es aproximadamente 2 -52 , lo que probablemente sea 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 sólo 122 bits de entropía. (No todos los bits de un UUID "aleatorio" se seleccionan al azar). Una cadena alfanumérica elegida al azar contiene más entropía en solo 21 caracteres.
Los UUID no son flexibles; Tienen una estructura y distribución estandarizadas. Ésta es su principal virtud y también su principal debilidad. Al colaborar con un tercero, la estandarización que ofrecen los UUID puede resultar útil. Para uso puramente interno, pueden resultar ineficientes.
Java proporciona una forma de hacer esto directamente. Si no quieres los guiones, son fáciles de quitar. Solo usauuid.replace("-", "")
import java.util.UUID;
public class randomStringGenerator {
public static void main(String[] args) {
System.out.println(generateString());
}
public static String generateString() {
String uuid = UUID.randomUUID().toString();
return "uuid = " + uuid;
}
}
Producción
uuid = 2d7428a6-b58c-4008-8575-f05549f16316
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static SecureRandom rnd = new SecureRandom();
String randomString(int len){
StringBuilder sb = new StringBuilder(len);
for(int i = 0; i < len; i++)
sb.append(AB.charAt(rnd.nextInt(AB.length())));
return sb.toString();
}