Алгоритм
Щоб створити випадковий рядок, об'єднайте символи, намальовані випадковим чином з набору прийнятних символів, поки рядок не досягне потрібної довжини.
Впровадження
Ось досить простий і дуже гнучкий код для генерації випадкових ідентифікаторів. Прочитайте інформацію, що випливає з важливих приміток до програми.
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);
}
}
Приклади використання
Створіть незахищений генератор для 8-символьних ідентифікаторів:
RandomString gen = new RandomString(8, ThreadLocalRandom.current());
Створіть захищений генератор для ідентифікаторів сеансу:
RandomString session = new RandomString();
Створіть генератор із зручними для читання кодами для друку. Рядки довші, ніж повні буквено-цифрові рядки, щоб компенсувати використання меншої кількості символів:
String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);
Використовувати як ідентифікатори сеансу
Створення ідентифікаторів сеансу, які можуть бути унікальними, недостатньо добре, або ви можете просто скористатися простим лічильником. Коли використовуються передбачувані ідентифікатори, зловмисники викрадають сеанси.
Існує напруга між довжиною та захищеністю. Коротші ідентифікатори простіше здогадатися, оскільки можливостей менше. Але довші ідентифікатори споживають більше пам’яті та пропускну здатність. Більший набір символів допомагає, але може спричинити проблеми з кодуванням, якщо ідентифікатори будуть включені в URL-адреси або повторно введені вручну.
Основне джерело випадковості або ентропія для ідентифікаторів сеансу має виходити з генератора випадкових чисел, призначеного для криптографії. Однак іноді ініціалізація цих генераторів може бути обчислювально дорогою або повільною, тому слід докласти зусиль для їх повторного використання, коли це можливо.
Використовувати як ідентифікатори об'єктів
Не кожна програма вимагає безпеки. Випадкове призначення може бути ефективним способом для декількох об'єктів генерувати ідентифікатори в спільному просторі без будь-якої координації чи розділення. Координація може бути повільною, особливо в кластерному або розподіленому середовищі, і розщеплення простору спричиняє проблеми, коли суб'єкти господарювання надто малі або занадто великі.
Ідентифікатори, згенеровані без вжиття заходів, щоб зробити їх непередбачуваними, повинні бути захищені іншими способами, якщо зловмисник зможе їх переглядати та маніпулювати, як це відбувається у більшості веб-додатків. Повинна бути окрема система авторизації, яка захищає об'єкти, ідентифікатор яких може вгадати зловмисник без дозволу доступу.
Слід також обережно використовувати ідентифікатори, які досить довгі, щоб зробити зіткнення малоймовірними, враховуючи передбачувану загальну кількість ідентифікаторів. Це називається "парадокс дня народження". Імовірність зіткнення, р , становить приблизно n 2 / (2q x ), де n - кількість фактично створених ідентифікаторів, q - кількість різних символів в алфавіті, а x - довжина ідентифікаторів. Це має бути дуже невелика кількість, наприклад 2-50 або менше.
Опрацювання цього показує, що ймовірність зіткнення між ідентифікаторами 500k 15 символів становить приблизно 2–52 , що, ймовірно, менше ймовірність, ніж невиявлені помилки космічних променів тощо.
Порівняння з UUID
Відповідно до їх специфікації, UUID не розроблені як непередбачувані, і їх не слід використовувати як ідентифікатори сеансу.
UUID в їх стандартному форматі займають багато місця: 36 символів лише 122 біти ентропії. (Не всі біти "випадкового" UUID вибрані випадковим чином.) Вибрана випадковим чином буквено-числова рядок пакує більше ентропії всього лише 21 символом.
UUID не є гнучкими; вони мають стандартизовану структуру та компонування. Це їхня головна чеснота, а також їх основна слабкість. У співпраці із стороною стороною може бути корисна стандартизація, запропонована UUID. Для чисто внутрішнього використання вони можуть бути неефективними.