Cybersecurity

AppSec concerns: UUID generation

Thought Leadership Team

Coalfire

Blog Images 2022 UUID tile

Background

During static analysis, one of the things the application security team checks for is strong random number generation for security sensitive contexts. We see weaknesses in this space quite often for temporary passwords and session identifiers, but an increasingly common variant is for universally unique identifiers (UUIDs).

The proposed UUID standard describes a UUID as:

“…128 bits long, and can guarantee uniqueness across space and time. UUIDs were originally used in the Apollo Network Computing System and later in the Open Software Foundation’s (OSF) Distributed Computing Environment (DCE), and then in Microsoft Windows platforms.” RFC 4122

They used them on the Apollo mission, how neat is that?

However, in a security context these values are not necessarily “guaranteed unique.” A hash collision can be caused due to the fact that the identifiers have a finite size, which means it is therefore possible for two entities to generate the same identifier. The generation process, or algorithm, needs to be selected so as to make this sufficiently improbable in practice.

Implementation

The generation process typically involves random number generation. RFC 4122, the RFC defining the UUID standard, recommends using a cryptographic-grade random number generator for the purposes of generating UUIDs (RFC 4122, p. 14). Using a statistical pseudo random number generator (PRNG) instead will pose the following problems:

  • Increased probability that two hosts will generate the same UUID.
  • Increased risk of an attacker being able to derive the statistical PRNG’s internal state, and then being able to guess future generated UUIDs.

Cryptographically secure PRNGs are designed to be non-reproducible, even if the attacker has knowledge of the algorithm in use. Furthermore, cryptographic PRNGs are designed to maintain much more internal state, often incorporating non-deterministic system parameters and hardware-based random sources.

One area where cryptographic PRNGs are difficult to implement correctly is the client side of web application systems. For example, consider this code from the Apache Cordova library (version 3.8.0):

function UUIDcreatePart(length) {
    var uuidpart = "";
    for (var i=0; i < length; i++) {
        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
        if (uuidchar.length == 1) {
            uuidchar = "0" + uuidchar;
        }
        uuidpart += uuidchar;
    }
    return uuidpart;
}


Whether or not the above code is immediately exploitable depends on how the UUID is used. However, the Math.Random() function is an example of a potentially insecure statistical pseudo-random number generator (PRNG).

PRNGs generate output that is ostensibly random and unpredictable. However, while their output may satisfy certain basic statistical properties, a skilled attacker can still predict the sequence of generated random values if they have basic knowledge of the algorithm used. Furthermore, statistical PRNGs typically contain very little state; their output is often based on the system date and time.

Conclusions

Under ordinary conditions, the probability of having two generated UUIDs collide is very small. However, if UUIDs are generated improperly, the probability of a collision increases considerably. Unfortunately, neither JavaScript nor Apache Cordova provide a standard way of generating cryptography-grade random values. Therefore, developers and operators must be cautious about accepting client-generated UUIDs by any server-side application.

In closing, keep the following guidelines in mind:

  • Generate UUIDs on the server, if possible. This will ensure a sufficiently strong algorithm can be used to generate the UUID.
  • Use a strong UUID algorithm. Choosing a cryptographically secure PRNG will reduce the chance of a collision. Most major development platforms have secure UUID libraries (e.g., Java’s uuid.randomUUID() method).
  • Plan for collisions. Ensure that applications and servers behave safely and consistently if they encounter identical UUIDs for different records or objects.
  • Don’t rely on UUIDs for security. Never use UUIDs for things like session identifiers. The standard itself warns implementors to “not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access, for example).”

UUID generation and management is going to be a growing space for security researchers and professionals due to their prevalence in Internet of Things (IoT) capable devices. For an interesting read on improper UUID management, please see the following article on Hackable Google Beacons made by Estimote, wherein the company tried to secure it’s implementation but still wound up vulnerable to Denial of Service and False Flag attacks.