Understanding SecureRandom in Modern Java: new SecureRandom() vs SecureRandom.getInstanceStrong()
For many Java developers,
generating cryptographically secure random values appears straightforward:
SecureRandom random = new SecureRandom();
or perhaps:
SecureRandom random = SecureRandom.getInstanceStrong();
Both approaches produce a SecureRandom instance. Both are
designed for cryptographic use cases. Both are significantly more secure than java.util.Random.
Yet beneath these seemingly simple APIs lies a surprisingly
complex interaction between the JVM, security providers, operating system entropy sources, and cryptographic standards.
Understanding these details is important because
the choice of random number generator can impact:
- Application startup time
- Cryptographic strength
- Portability across platforms
- Container and cloud deployment behavior
- Compliance requirements
- Operational reliability
This article examines how Java’s secure random number generation works, what differentiates new SecureRandom() from
SecureRandom.getInstanceStrong(), and which approach should be preferred in modern enterprise environments.
Why Cryptographically Secure Randomness
Matters
Modern applications rely on secure randomness far more often than many developers realize.
Common examples include:
- Session identifiers
- JWT signing keys
- Password reset tokens
- OAuth state parameters
- CSRF protection
- TLS handshakes
- Key generation
- Digital signatures
- Encryption initialization vectors
- Nonces
The fundamental requirement is unpredictability.
An attacker capable of predicting future outputs of a random number generator can often compromise the entire
security model of an application.
This is why Java provides SecureRandom, a cryptographically secure pseudo-random number generator (CSPRNG), specifically
designed to withstand prediction attacks.
What Happens When You Call new SecureRandom()?
Consider the following code:
SecureRandom random = new SecureRandom();
Most developers assume this directly instantiates a specific implementation.
In
reality, the JVM delegates the selection to the Java Security Provider architecture.
At runtime, Java:
- Inspects the configured security providers
- Searches for available
SecureRandomimplementations - Selects the preferred implementation
- Instantiates and seeds it
The resulting algorithm depends on several factors:
- JDK version
- Operating system
- Security provider configuration
- Security policy
On contemporary JDKs (17, 21 and beyond), the implementation is frequently one of:
DRBG
or
NativePRNG
depending on platform and configuration.
You can verify the actual implementation:
SecureRandom random = new SecureRandom(); System.out.println(random.getAlgorithm()); System.out.println(random.getProvider());
Typical output:
DRBG SUN
or:
NativePRNG SUN
The important observation is that new SecureRandom() does not imply a particular algorithm. It requests the JVM’s default
secure random implementation.
Enter SecureRandom.getInstanceStrong()
Java 8 introduced a new API:
SecureRandom random =SecureRandom.getInstanceStrong();
This method has a different objective.
Rather than selecting the
default implementation, it requests the strongest secure random generator configured on the platform.
Internally, Java consults the following security property:
securerandom.strongAlgorithms
located in:
$JAVA_HOME/conf/security/java.security
Typical values may look like:
securerandom.strongAlgorithms= NativePRNGBlocking:SUN, DRBG:SUN
Java attempts to instantiate the first suitable candidate.
Unlike new, the resulting implementation is explicitly influenced by the platform’s definition of “strong”.
SecureRandom()
Historical Context: /dev/random
versus /dev/urandom
To understand why this distinction exists, we need to revisit Linux entropy management.
Historically, Linux exposed two primary
entropy interfaces:
/dev/random
and
/dev/urandom
/dev/random
- Uses entropy collected from environmental noise
- May block when entropy is considered insufficient
- Traditionally regarded as the most conservative source
/dev/urandom
- Non-blocking
- Uses a cryptographically secure internal PRNG
- Continues producing output even when entropy pools are depleted
For many years, security guidance often favored /dev/random for highly sensitive operations.
Consequently, some JVM implementations mapped “strong”
random generation to entropy sources capable of blocking.
This design decision eventually led to one of the most infamous operational issues in Java security.
The
Startup Hang Problem
Many developers encountered situations similar to the following:
SecureRandom random =SecureRandom.getInstanceStrong();
Application startup would appear frozen:
Starting Spring Boot application...
And then nothing.
The process was waiting for entropy.
This behavior was especially common in:
- Virtual machines
- Cloud environments
- Docker containers
- Kubernetes clusters
- Minimal Linux distributions
The issue was not Java itself. The underlying operating system simply refused to provide additional entropy at that moment.
How Modern Linux Changed the
Equation
Modern Linux kernels use the getrandom() system call and maintain cryptographically strong entropy pools that become secure shortly after system
initialization.
Today:
- Linux entropy management is significantly improved
- OpenJDK implementations have evolved accordingly
- Container platforms inherit entropy from mature host systems
- Blocking behavior is far less common
As a result, the historical distinction between /dev/random and /dev/urandom has become much less relevant for most production workloads.
The Rise of DRBG
Since JDK 9, Java includes support for NIST SP 800-90A Deterministic Random Bit Generators (DRBGs).
SecureRandom random =SecureRandom.getInstance("DRBG");
DRBG implementations provide:
- Well-defined cryptographic properties
- Explicit security strength
- Standardized behavior
- Alignment with modern compliance frameworks
What Should You Use in Spring Boot on EKS?
Consider a typical modern deployment:
Spring Boot↓ Container↓ Amazon EKS↓ EC2↓ Linux Kernel
For this environment, the recommended choice is usually:
private static final SecureRandom RANDOM =new SecureRandom();
or, when explicit algorithm selection is desired:
SecureRandom.getInstance("DRBG");
Using SecureRandom.getInstanceStrong() is generally unnecessary unless your
organization has specific compliance or regulatory requirements demanding the strongest available implementation.
Conclusion
The distinction between new and
SecureRandom()SecureRandom.getInstanceStrong() reflects the evolution of both operating systems and the JVM.
For most enterprise Java workloads,
including Spring Boot applications deployed on Kubernetes, EKS, ECS, OpenShift, or traditional Linux servers, new SecureRandom() provides an excellent balance of
security, performance, portability, and operational reliability.
When stronger guarantees or compliance requirements exist, DRBG or getInstanceStrong() may
be appropriate. However, these should be deliberate architectural choices rather than defaults applied indiscriminately.
In modern Java platforms, secure randomness is no
longer primarily about finding the strongest entropy source. It is about selecting a solution that delivers robust cryptographic guarantees while remaining operationally
predictable at scale.