He estado buscando un algoritmo Java simple para generar una cadena alfanumérica pseudo-aleatoria. En mi situación se utilizaría como un identificador de sesión / clave única que sería "probablemente" ser único sobre 500K+
generación (mis necesidades don't realmente requieren algo mucho más sofisticado).
Lo ideal sería poder especificar una longitud en función de mis necesidades de unicidad. Por ejemplo, una cadena generada de longitud 12 podría ser algo así como "AEYGF7K0DM1X"
.
Para generar una cadena aleatoria, concatena caracteres extraídos al azar del conjunto de símbolos aceptables hasta que la cadena alcance la longitud deseada.
Aquí hay un código bastante simple y muy flexible para generar identificadores aleatorios. Lea la información que sigue para las notas de aplicación importantes.
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
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);
}
}
Crear un generador inseguro para identificadores de 8 caracteres:
RandomString gen = new RandomString(8, ThreadLocalRandom.current());
Crear un generador seguro para los identificadores de sesión:
RandomString session = new RandomString();
Crear 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);
Generar identificadores de sesión que probablemente sean únicos no es suficiente, o se podría utilizar un simple contador. Los atacantes secuestran las sesiones cuando se utilizan identificadores predecibles.
Existe una tensión entre la longitud y la 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 mayor de símbolos ayuda, pero puede causar problemas de codificación si los identificadores se incluyen en las URL o se vuelven a introducir a mano.
La fuente subyacente de aleatoriedad, o entropía, para los identificadores de sesión debería proceder de un generador de números aleatorios diseñado para la criptografía. Sin embargo, la inicialización de estos generadores puede ser a veces costosa o lenta desde el punto de vista computacional, por lo que debe hacerse un esfuerzo para reutilizarlos cuando sea posible.
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 la división de un espacio causa problemas cuando las entidades terminan con acciones demasiado pequeñas 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 ocurre 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 hay que tener cuidado de utilizar identificadores lo suficientemente largos como para que las colisiones sean poco probables dado el número total de identificadores previsto. Esto se conoce como "la paradoja del cumpleaños". La probabilidad de una colisión, p, es aproximadamente n2/(2qx), 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.
Si lo calculamos, la probabilidad de colisión entre 500.000 identificadores de 15 caracteres es de aproximadamente 2‑52, lo que probablemente sea menos probable que los errores no detectados de los rayos cósmicos, etc.
Según su especificación, los UUIDs no están diseñados para ser impredecibles, y no deberían ser utilizados 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 sólo 21 caracteres.
Los UUID no son flexibles; tienen una estructura y un diseño estandarizados. Esta es su principal virtud y también su principal debilidad. Cuando se colabora con una parte externa, la estandarización que ofrecen los UUID puede ser útil. Para un uso puramente interno, pueden ser ineficaces.
Java ofrece una forma de hacerlo directamente. Si no quieres los guiones, son fáciles de eliminar. Sólo tiene que utilizar uuid.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;
}
}
Salida:
uuid = 2d7428a6-b58c-4008-8575-f05549f16316
Aquí está en Java:
import static java.lang.Math.round;
import static java.lang.Math.random;
import static java.lang.Math.pow;
import static java.lang.Math.abs;
import static java.lang.Math.min;
import static org.apache.commons.lang.StringUtils.leftPad
public class RandomAlphaNum {
public static String gen(int length) {
StringBuffer sb = new StringBuffer();
for (int i = length; i > 0; i -= 12) {
int n = min(12, abs(i));
sb.append(leftPad(Long.toString(round(random() * pow(36, n)), 36), n, '0'));
}
return sb.toString();
}
}
Aquí hay un ejemplo de ejecución:
scala> RandomAlphaNum.gen(42)
res3: java.lang.String = uja6snx21bswf9t89s00bxssu8g6qlu16ffzqaxxoy