Skip to content

Implement static analysis rule "Secure random number generators should not output predictable values" in Crypto module #8258

@nureka-rodrigo

Description

@nureka-rodrigo

Description

Random values are used in many security-critical contexts such as:

  • Generating authentication tokens or session IDs
  • Creating password reset links
  • Producing cryptographic keys
  • Implementing security mechanisms like CSRF tokens

Using predictable random values in these scenarios creates serious security vulnerabilities. Attackers who can predict these "random" values could:

  1. Hijack user sessions
  2. Access restricted resources
  3. Impersonate users
  4. Bypass security controls
  5. Break cryptographic protections

Standard random number generators (like those used for random sampling or games) are designed for statistical randomness, not security. They are often:

  • Initialized with predictable seeds (like current time)
  • Based on deterministic algorithms that can be reverse-engineered
  • Vulnerable to state reconstruction attacks

For security purposes, cryptographically secure pseudo-random number generators (CSPRNGs) must be used instead.

Non-compliant Code

public function main() returns error? {
    byte[16] key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

    foreach int i in 0 ... 15 {
        key[i] = <byte>(check random:createIntInRange(0, 255));
    }
    
    io:println("Key: ", key);
}

In this non-compliant example, the code uses Ballerina's standard random:createIntInRange() function which is not cryptographically secure. This function uses a Linear Congruential Generator (LCG) with a time-based seed, making it predictable and unsuitable for security-sensitive operations like generating cryptographic keys.

Compliant Code

public function main() returns error? {
    byte[16] key = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

    // Use the Java SecureRandom implementation directly
    handle secureRandomObj = newSecureRandom();

    foreach int i in 0 ... 15 {
        key[i] = <byte>getSecureRandomInt(secureRandomObj, 256);
    }

    io:println("Key: ", key);
}

isolated function newSecureRandom() returns handle = @java:Constructor {
    'class: "java.security.SecureRandom"
} external;

isolated function getSecureRandomInt(handle secureRandomObj, int bound) returns int = @java:Method {
    name: "nextInt",
    'class: "java.security.SecureRandom",
    paramTypes: ["int"]
} external;

Ballerina currently does not provide a dedicated cryptographically strong random number generator (CSPRNG) API in its standard libraries. The solution shown above is a workaround that leverages Ballerina's Java interoperability to access Java's SecureRandom class. While effective, this is not a permanent solution and requires Java interop capabilities which may not be available in all Ballerina runtime environments.

This workaround should be used until Ballerina implements native CSPRNG functionality in its standard libraries. Developers should monitor Ballerina updates for proper cryptographically secure random number generation support in the future.

Reference

SonarQube Rule: Secure random number generators should not output predictable values

Version

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions