JDK-8225404 : Potential DOS using UUID.fromString
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 8u212
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_10
  • CPU: x86_64
  • Submitted: 2019-06-02
  • Updated: 2019-06-06
  • Resolved: 2019-06-06
Related Reports
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
In Java 8 UUID.fromString parses the string by using String.split without any validation before that [1].
This can be quite problematic because that method is rather inefficient. Since UUIDs are used by web services which might not perform additional validation before using UUID.fromString this might allow causing a Denial of Service.
In Java 9 the implementation has been changed (JDK-8006627) and is not affected by this problem [2].

[1] https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/d0cccfd32b1e/src/share/classes/java/util/UUID.java#l192
[2] https://hg.openjdk.java.net/jdk/jdk/file/905b2a416250/src/java.base/share/classes/java/util/UUID.java#l198

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Parsing the ~42MB string consisting only of hypens (-) should fail fast.
ACTUAL -
Parsing takes multiple seconds and consumes ~800MB before failing.

---------- BEGIN SOURCE ----------
import java.util.Arrays;
import java.util.UUID;

public class UUIDTest {
    public static void main(String[] args) {
        final char[] uuidStringChars = new char[Integer.MAX_VALUE / 100];
        Arrays.fill(uuidStringChars, '-');
        
        final long preString = getUsedMemory();
        final String uuidString = new String(uuidStringChars);
        printUsedMemory("String", getUsedMemory() - preString);
        
        System.gc();
        final long preUuid = getUsedMemory();
        
        try {
            UUID.fromString(uuidString);
        }
        catch (final IllegalArgumentException e) {
            printUsedMemory("UUID parsing", getUsedMemory() - preUuid);
        }
    }
    
    private static long getUsedMemory() {
        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    }
    
    private static void printUsedMemory(final String message, final long usedMemory) {
        System.out.println(message + ": " + usedMemory / 1_000_000 + "MB (" + usedMemory + " bytes)");
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Validate the UUID string length before calling UUID.fromString, a UUID string longer than 36 characters is malformed and will not work in Java 9(+) anyways.

FREQUENCY : always



Comments
Please refer to the comment https://bugs.openjdk.java.net/browse/JDK-8159339?focusedCommentId=13963085&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13963085 from bug JDK-8159339 which states the reason for not including the change in JDK 8 update releases.
06-06-2019