Algorytm
Aby wygenerować losowy ciąg, połącz znaki losowe z zestawu dopuszczalnych symboli, aż ciąg osiągnie pożądaną długość.
Realizacja
Oto dość prosty i bardzo elastyczny kod do generowania losowych identyfikatorów. Przeczytaj poniższe informacje, aby uzyskać ważne uwagi dotyczące aplikacji.
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);
}
}
Przykłady użycia
Utwórz niepewny generator dla 8-znakowych identyfikatorów:
RandomString gen = new RandomString(8, ThreadLocalRandom.current());
Utwórz bezpieczny generator identyfikatorów sesji:
RandomString session = new RandomString();
Utwórz generator z łatwymi do odczytania kodami do drukowania. Ciągi są dłuższe niż pełne ciągi alfanumeryczne, aby zrekompensować użycie mniejszej liczby symboli:
String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);
Użyj jako identyfikatorów sesji
Generowanie identyfikatorów sesji, które prawdopodobnie będą unikalne, nie jest wystarczająco dobre lub możesz po prostu użyć prostego licznika. Atakujący przejmują sesje, gdy używane są przewidywalne identyfikatory.
Istnieje napięcie między długością a bezpieczeństwem. Krótsze identyfikatory są łatwiejsze do odgadnięcia, ponieważ jest mniej możliwości. Ale dłuższe identyfikatory zużywają więcej pamięci i przepustowości. Większy zestaw symboli pomaga, ale może powodować problemy z kodowaniem, jeśli identyfikatory są zawarte w adresach URL lub ponownie wprowadzone ręcznie.
Podstawowym źródłem losowości lub entropii dla identyfikatorów sesji powinien być generator liczb losowych przeznaczony do kryptografii. Jednak inicjowanie tych generatorów może czasami być drogie obliczeniowo lub powolne, więc należy dołożyć starań, aby ponownie z nich korzystać, jeśli to możliwe.
Użyj jako identyfikatorów obiektów
Nie każda aplikacja wymaga bezpieczeństwa. Losowe przypisywanie może być skutecznym sposobem dla wielu podmiotów do generowania identyfikatorów we wspólnej przestrzeni bez jakiejkolwiek koordynacji lub partycjonowania. Koordynacja może być powolna, szczególnie w środowisku klastrowym lub rozproszonym, a podział przestrzeni powoduje problemy, gdy jednostki kończą się udziałami, które są zbyt małe lub zbyt duże.
Identyfikatory generowane bez podejmowania działań, które czynią je nieprzewidywalnymi, powinny być chronione innymi środkami, jeśli osoba atakująca może je wyświetlić i manipulować, jak to ma miejsce w większości aplikacji internetowych. Powinien istnieć oddzielny system autoryzacji, który chroni obiekty, których identyfikator może odgadnąć osoba atakująca bez pozwolenia na dostęp.
Należy również zachować ostrożność, aby używać identyfikatorów wystarczająco długich, aby kolizje były mało prawdopodobne, biorąc pod uwagę przewidywaną całkowitą liczbę identyfikatorów. Nazywa się to „paradoksem urodzinowym”. Prawdopodobieństwo kolizji, p , wynosi w przybliżeniu n 2 / (2q x ), gdzie n jest liczbą faktycznie wygenerowanych identyfikatorów, q jest liczbą różnych symboli w alfabecie, a x jest długością identyfikatorów. Powinna to być bardzo mała liczba, na przykład 2–50 lub mniejsza.
Wypracowanie tego pokazuje, że szansa kolizji między 500k 15-znakowymi identyfikatorami wynosi około 2–52 , co jest prawdopodobnie mniej prawdopodobne niż niewykryte błędy promieni kosmicznych itp.
Porównanie z UUID
Zgodnie z ich specyfikacją identyfikatory UUID nie są zaprojektowane jako nieprzewidywalne i nie powinny być używane jako identyfikatory sesji.
Identyfikatory UUID w standardowym formacie zajmują dużo miejsca: 36 znaków dla zaledwie 122 bitów entropii. (Nie wszystkie bity „losowego” UUID są wybierane losowo.) Losowo wybrany ciąg alfanumeryczny zawiera więcej entropii w zaledwie 21 znakach.
UUID nie są elastyczne; mają znormalizowaną strukturę i układ. To jest ich główna cnota, a także ich główna słabość. Podczas współpracy z podmiotem zewnętrznym pomocna może być standaryzacja oferowana przez UUID. Do użytku wyłącznie wewnętrznego mogą być nieefektywne.