34

As previous discussed, confirmation emails should have a unique, (practically) un-guessable code--essentially a one-time password--in the confirmation link.

The UUID.randomUUID() docs say:

The UUID is generated using a cryptographically strong pseudo random number generator.

Does this imply that the the UUID random generator in a properly implemented JVM is suitable for use as the unique, (practically) un-guessable OTP?

Community
  • 1
  • 1
cqcallaw
  • 1,463
  • 3
  • 18
  • 29
  • 2
    You might be interested in [my answer to another question,](http://stackoverflow.com/a/41156/3474) which will give you more security with fewer digits... if that matters. – erickson Jun 14 '12 at 05:09
  • 2
    Also see discussion here: https://security.stackexchange.com/questions/890/are-guids-safe-for-one-time-tokens – steve cook Aug 25 '17 at 07:06

8 Answers8

22

if you read the RFC that defines UUIDs, and which is linked to from the API docs, you'll see that not all bits of the UUID are actually random (the "variant" and the "version" are not random). so a type 4 UUID (the kind that you intend to use), if implemented correctly, should have 122 bits of (secure, for this implementation) random information, out of a total size of 128 bits.

so yes, it will work as well as a 122 bit random number from a "secure" generator. but a shorter value may contain a sufficient amount of randomness and might be easier for a user (maybe i am the only old-fashioned person who still reads email in a terminal, but confirmation URLs that wrap across lines are annoying....).

Mark Gee
  • 103
  • 1
  • 3
andrew cooke
  • 45,717
  • 10
  • 93
  • 143
  • Others provided similar answers, but this seemed to be the most complete and informative. Thanks. – cqcallaw Jun 14 '12 at 04:25
  • 13
    Actually, the RFC explicitly cautions against using UUIDs as security tokens: "Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example." A UUID4 generated **with a secure RNG** will be nearly impossible to guess, but the standard explicitly allows insecure RNGs(!). http://tools.ietf.org/html/rfc4122#section-6 (Apologies for resurrecting a very old comment, but security is everyone's concern.) – Mike McCoy Nov 24 '14 at 17:47
  • Actually the point here is not what the standard of the UUID says, but how safe the Java UUID implementation is in practice. So, how secure is the Java RNG used for UUIDs? – Salvioner Aug 06 '18 at 08:00
18

No. According to the UUID spec:

Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example. A predictable random number source will exacerbate the situation.

Also, UUIDs only have 16 possible characters (0 through F). You can generate a much more compact and explicitly secure random password using SecureRandom (thanks to @erickson).

import java.security.SecureRandom;
import java.math.BigInteger;

public final class PasswordGenerator {
    private SecureRandom random = new SecureRandom();

    public String nextPassword() {
        return new BigInteger(130, random).toString(32);
    }
}

P.S.

I want to give a clear example of how using UUID as a security token may lead to issues:

In uuid-random we discovered an enormous speed-boost by internally re-using random bytes in a clever way, leading to predictable UUIDs. Though we did not release the change, the RFC allows it and such optimizations could sneak into your UUID library unnoticed.

jchook
  • 6,690
  • 5
  • 38
  • 40
  • 18
    UUID spec != Java implementation. While the spec doesn't require the UUID to be secure, the Java implementation actually provides 122 bits of secure randomness. See also http://stackoverflow.com/a/7532965/47528 – Dan Mar 25 '17 at 17:12
  • 3
    I would still recommend using a crypto lib explicitly. – jchook Mar 25 '17 at 22:21
  • 2
    Yes, definitely ;-) When it comes to security, it's better to be cautious and explicit. You wouldn't use UUID.randomUUID() for military-grade systems. But if the question is "Am I introducing a security hole by using UUID.randomUUID() for tokens?" then the answer is no. – Dan Mar 26 '17 at 11:35
  • 1
    This answer as it stands is just misinformation. While it's acceptable to say, "UUID's shouldn't generally be trusted as OTPs," stating out of hand that Java's shouldn't be trusted is factually incorrect. In addition, without a concrete recommendation for an alternative OTP generator, this answer is most unhelpful. – Tim Pote Jun 16 '17 at 15:40
  • 3
    Thanks for the feedback. Edited to include a solution. – jchook Jun 17 '17 at 04:06
11

Yes, using a java.util.UUID is fine, randomUUID methods generates from a cryptographically secure source. There's not much more that needs to be said.

Here's my suggestion:

  1. Send the user a link with a huge password in it as the URL argument.
  2. When user clicks the link, write your backend so that it will determine whether or not the argument is correct and that the user is logged in.
  3. Invalidate the UUID 24 hours after it has been issued.

This will take some work, but it's necessary if you really care about writing a robust, secure system.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • 1
    Your suggestion is my exact intention, except I intend to invalidate the UUID as soon as the confirmation URL is visited and confirmation is complete. – cqcallaw Jun 14 '12 at 04:28
  • 2
    @cqcallaw what if user never visits the url? I always invalidate such keys after 1st usage or after a couple of hours, whatever comes 1st. – Lukas Liesis Feb 06 '19 at 15:41
1

Password strength can be quantified based on the required entropy(higher the better).

For a binary computer,

entropy = password length * log2(symbol space)
symbol space is the total unique symbols(characters) available for selection

For a normal english speaking user with qwerty keyboard,

  1. symbols are selected from 52 characters(26 * 2 for both cases) + 10 numbers + maybe 15 other characters like (*, + -, ...), the general symbol space is around 75.
  2. if we expect a minimum password length of 8:
entropy = 8 * log275 ~= 8 * 6.x ~= 50

To achieve an entropy(50) for autogenerated one-time passwords with only hexadecimal (16 symbol space = 0-9,a-f),

password length = 50 / log216 = 50 / 4 ~= 12

If the application can be relaxed to consider the complete case sensitive english alphabets and numbers, the sample space will be 62 (26 * 2 + 10),

password length = 50 / log262 = 50 / 6 ~= 8

This has reduced the number of characters to be typed by the user to 8 (from 12 with hexadecimal).

With UUID.randomUUID(), two main concerns are

  1. user has to enter 32 characters (not user friendly)
  2. implementations has to ensure uniqueness criteria (close coupling with library versions and language dependencies)

I understand this is not a direct answer and its really up to the application owner to choose the best strategy considering the security and usability constraints.

Personally, i will not use UUID.randomUUID() as one-time password.

Thiyanesh
  • 2,360
  • 1
  • 4
  • 11
-2

The point of the random code for a confirmation link is that the attacker should not be able to guess nor predict the value. As you can see, to find the correct code to your confirmation link, a 128bits length UUID yields 2^128 different possible codes, namely, 340,282,366,920,938,463,463,374,607,431,768,211,456 possible codes to try. I think your confirmation link is not for launching a nuclear weapon, right? This is difficult enough for attacker to guess. It's secure.

-- update --

If you don't trust the cryptographically strong random number generator provided, you can put some more unpredictable parameters with the UUID code and hash them. For example,

code = SHA1(UUID, Process PID, Thread ID, Local connection port number, CPU temperature)

This make it even harder to predict.

Fang-Pen Lin
  • 13,420
  • 15
  • 66
  • 96
  • 2
    Just the number of bits generated doesn't make it unpredictable. `java.util.Random` can be used to get 128 bits of data, but that doesn't mean it's anything like secure. – Louis Wasserman Jun 14 '12 at 03:25
  • 3
    Nowadays, people attacks for making money, and you have a limited budget. Nothing is unbreakable. So how secure it should be? The point of security is - how much do they cost to break it, and what benefit they can get? If it's a code for confirmation link of a common website, then this is secure enough. If this is a code for nuclear weapon, then I wouldn't say so. For me, the definition of secure is - The cost to break it >> The revenue expectation. When it cost too much to break it, and little revenue you can make by break it, then it's safe. – Fang-Pen Lin Jun 14 '12 at 03:36
  • There is a topic is about randomUUID http://stackoverflow.com/questions/2513573/how-good-is-javas-uuid-randomuuid – Fang-Pen Lin Jun 14 '12 at 03:58
  • 2
    http://docs.oracle.com/javase/6/docs/api/java/security/SecureRandom.html "A cryptographically strong random number minimally complies with the statistical random number generator tests specified in FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. Additionally, SecureRandom must produce non-deterministic output. Therefore any seed material passed to a SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in RFC 1750: Randomness Recommendations for Security." – Fang-Pen Lin Jun 14 '12 at 04:02
  • So, if what they said is true, UUID could be secure enough. But anyway, if you don't trust the random number generator, you can put anything you think that's unpredictable and hash them with the UUID code. Connection local port, PID, thread ID, cpu temperature .... That just make it harder to predict. – Fang-Pen Lin Jun 14 '12 at 04:06
  • There are two threat models: 1) an attacker attempting to guess a confirmation code 2) an attacker attempting to guess the _next_ confirmation code based on one they've received. Simply having a large number of possible codes does not guarantee protection from either attack. If the confirmation code generator only uses the first 100 possible values out of 2^128 possible values, it's trivial to guess the confirmation code. If the code generator simply takes the next sequential value, it's easy to guess the next code if the attacker has an existing code. So, unpredictable output is important. – cqcallaw Jun 14 '12 at 04:18
  • Yes, UUIDs appear to be more secure than `java.util.Random`, but this answer didn't give _any_ indication of the reasons why. – Louis Wasserman Jun 14 '12 at 14:51
-3

I think this should be suitable, as it is generated randomly rather than from any specific input (ie you're not feeding it with a username or something like that) - so multiple calls to this code will give different results. It states that its a 128-bit key, so its long enough to be impractical to break.

Are you then going to use this key to encrypt a value, or are you expecting to use this as the actual password? Regardless, you'll need to re-interpret the key into a format that can be entered by a keyboard. For example, do a Base64 or Hex conversion, or somehow map the values to alpha-numerics, otherwise the user will be trying to enter byte values that don't exist on the keyboard.

wattostudios
  • 8,666
  • 13
  • 43
  • 57
  • I plan to embed the confirmation code in a confirmation URL that the email recipient clicks to complete confirmation. No user input should be necessary... – cqcallaw Jun 14 '12 at 04:21
-4

It is perfect as one time password, as even I had implemented the same for application on which am working. Moreover, the link which you've shared says it all.

Anuj Balan
  • 7,629
  • 23
  • 58
  • 92
-4

I think java.util.UUID should be fine. You can find more information from this article:

Mercury
  • 33
  • 3