Secure generation of random IDs and passwords

The Apache Commons Lang library has a handy set of random string generators, enclosed inside the RandomStringUtils class. However, these are not cryptographically secure generators by default, which can trigger warnings in platforms like Veracode (for example CWE-331: Insufficient Entropy).

It’s even more important when you think what the random strings are used for. Most of the time these are some session, token or debugging identifiers, or even passwords. Such strings shouldn’t be predictable.

The default java.util.Random implementation is not cryptographically secure, and yet it is used by default in shorthand RandomStringUtils methods. However it is possible to pass a custom generator as the last argument, for example java.security.SecureRandom:

final SecureRandom random = new SecureRandom();
final String id = RandomStringUtils.random(10, 0, 0, true, true, null, random);
System.out.println(id);  // prints 10 random alphanumeric characters

A more sophisticated yet cleaner way might be to use RandomStringGenerator from Apache Commons Text together with SecureTextRandomProvider from Apache Syncope. Unfortunately, the latter class was removed in Syncope 2.1 and I couldn’t find any alternative.

Looks like Apache doesn’t like providing cryptographically secure random generators or even interfaces for them. The Apache Commons Random Numbers Generators documentation says: “The current design has made no provision for features generally needed for cryptography applications (e.g. strong unpredictability).”

One more library worth checking out is Passay. Its primary responsibility is to maintain a company’s password policy, and the library can be also used to generate random passwords according to the company rules. Of course you can provide SecureRandom as the source of randomness:

final SecureRandom random = new SecureRandom();
final PasswordGenerator generator = new PasswordGenerator(random);
final CharacterRule alphabet = new CharacterRule(EnglishCharacterData.Alphabetical);
final CharacterRule digits = new CharacterRule(EnglishCharacterData.Digit);
final String id = generator.generatePassword(10, alphabet, digits);
System.out.println(id);

This was just a basic example; Passay accepts more complex rules, for example a minimum number of letters, digits or special characters in a password.

Final thoughts

Use SecureRandom whenever you need to generate a random string.

Never use regular expressions to validate passwords against the company policy. Just don’t. Or you will end up with monsters like this (true story):

String PASSWORD_REGEX = "^[A-Za-z0-9!@#$%^&*()\-_=+:;'\"<>,.\\]{8,}$";