27

I'd like to use a V4 UUID / GUID for authenticating users. To be specific, the user would have to paste the UUID into a text field to gain access to their account. The UUID would be given to them at the time of registration. The UUID would be combined with a username (public) when authing.

Assume normal security practices are in place (SSL, DB holding the UUIDs is encrypted at rest, guards against brute force attacks, UUID would not be passed in a URL, etc). Assume that the application isn't for anything extremely important (banking) but is still fairly important (pretend it is domain names, for the sake of argument). Don't worry about the usability issues that the user might have. I'm just concerned about security.

  • Given the above, is this still a bad idea?
  • Do you think this is less secure than username / pass?
  • Would slamming two UUIDs together be more secure?

My goal here is to not be storing personal data of any kind (email / pass). My hope is that this is a viable alternative.

0

4 Answers 4

28

UUIDs do not generally guarantee unpredictability or any security properties. As RFC 4122 says (section 6):

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.

What you require here is a cryptographically secure random number generator. Some UUID implementations are driven off such RNGs, but that's an implementation choice, not a guarantee. The ITU standard explicitly says that the use of cryptographic random number is recommended, which clearly implies it's not a requirement (p. 10):

The use of cryptographic-quality random numbers is strongly recommended in order to reduce the probability of repeated values.

And it turns out that some UUID implementations are not secure. For example, at least some versions of Google's V8 Javascript engine use a non-cryptographic PRNG for random UUID generation. The link describes how to attack such UUIDs—with a couple of lines of code, an attacker who sees one such UUID can reconstruct the PRNG's state when it output that UUID, which allows them to predict all subsequent UUIDs.

So I would not use UUIDs as cryptographic secrets—I'd interface directly with the cryptographic RNG, at least to make the intent of the code evident.

The bigger problem is that your users wouldn't be able to remember such tokens; they'd have to store them somewhere secure, and you'd be providing no assistance for so doing. The unobvious but actually very natural alternative here is to use a multi-factor authentication system based on passwords and secret keys, like TOTP. For example, if you build an integration with Google Authenticator or Authy, your users get the benefit of those vendors' user-side apps to store and manage the shared secret key.

6
  • 3
    Luis, my understanding is that a V4 UUID is random and not predictable (and could actually have collisions).
    – legeek
    Commented Apr 13, 2017 at 0:33
  • @legeek: The RFC—which is one of the documents that officially defines what UUIDs are—says otherwise, as I quoted. Commented Apr 13, 2017 at 0:43
  • 15
    @rook: If the fact that I've quoted official documents saying otherwise doesn't convince you, I don't know what possibly could. Commented Apr 13, 2017 at 1:12
  • 1
    @Luis Casillas I've read the source code for UUID4 generation for every major language. This is my job.
    – rook
    Commented Apr 13, 2017 at 1:25
  • 10
    @rook: It's been a while since this conversation, but I've updated my answer with a link to a real-life example of an insecure random UUID generator. Commented Jul 21, 2017 at 18:39
6

V4 UUID is quite commonly used to create API authentication tokens, like basic-auth or Oauth2 bearer tokens. As per RFC-4122, The version 4 UUID is meant for generating UUIDs from truly-random or pseudo-random numbers. Most commonly used V4-UUID generators make use of cryptographically secure random number generator. For example the github.com/google/uuid makes use of crypto/rand package.

For user-authentication, some of the best practices includes strong password policy (minimum length, special characters, not allow name/birthday etc), suggested strong password, at least 2-factor authentication etc. Depending upon the use-case, V4-UUID could be an option for first-factor generated token. Just make sure that V4-UUID generator makes use of cryptographically secure cryptographically secure random number generator.

3

You're just describing a scheme where the UUID simply becomes a password.

There's nothing especially secure or insecure about this, aside from no person ever going to be able to pick a "weak" password, but on the other hand, half of the people going to store their password unencrypted.

I don't really see why you'd do this to people. You're not going to make yourself very popular by denying amateurs the chance to pick a password they can remember nor experts the chance to generate one they deem secure themselves.

Also, I personally think individual bank account passwords are worth way less (considering banks have been 2-factoring wire transfers, at least in Europe, since more than 25 years now with transaction ID one time pads) than domain control (I can hardly ruin someone's business by looking at his bank account unless I plan to use it to mess with him based on other info, but I can easily ruin him by rerouting all his email through my servers by manipulating the MX record of their domain, and selectively letting through CEO mail and answering in their place. Oh, and you know, if they have an online business, actually abuse their web presence to the fullest extent).

So:

Given the above, is this still a bad idea?

Yes, inventing new auth schemes is usually a bad idea.

Do you think this is less secure than username / pass?

Depends on your clients, and as usual, on your attack scenario.

Would slamming two UUIDs together be more secure?

It would lead to longer random sequences, so yes, but then, why not use a longer random sequence from the start?

This all feels like you didn't think this through.

1
  • Thanks Marcus. Again, the user experience isn't the concern at the moment. I'm fully aware of the downside. Appreciate the answer.
    – legeek
    Commented Apr 13, 2017 at 0:31
3

I'd argue that UUIDv4 is not strong enough for conformance with some standards.

For example, RFC6819, OAuth 2.0 Threat Model and Security Considerations requires:

When creating secrets not intended for usage by human users (e.g., client secrets or token handles), the authorization server should include a reasonable level of entropy in order to mitigate the risk of guessing attacks. The token value should be >=128 bits long and constructed from a cryptographically strong random or pseudo-random number sequence (see [RFC4086] for best current practice) generated by the authorization server.

Strictly speaking, UUIv4 is “>=128 bits long” but I think the intent is actually to say that the token should have at least 128 bit of entropy. UUIDv4 only has 122 bits of entropy.

RFC6747, The OAuth 2.0 Authorization Framework says:

The probability of an attacker guessing generated tokens (and other credentials not intended for handling by end-users) MUST be less than or equal to 2^(-128) and SHOULD be less than or equal to 2^(-160).

which I believe is supposed to mean that the tokens for Oauth MUST have at least 128 bits of entropy and SHOULD have at least 160 bits of entropy.

Note that many OAuth implementations actually use UUIDv4 tokens in practice.

If you want to generate a random password/token, I'd suggest something like (example in Node.js):

crypto.randomBytes(160/8).toString('base64').replace(/=/g,'')

Or in pure JavaScript (https secure context only):

// 1. Unsigned 8-bit integer array with a length of 20, equivalent to 160 bits.
const array = new Uint8Array(160 / 8);

// 2. Fill the array with cryptographically strong random values.
crypto.getRandomValues(array);

// 3. Convert the array into a base64 string.
const base64String = btoa(String.fromCharCode(...array));

// 4. Convert the base64 string into a base64 url safe string.
const base64StringUrlEncoded = base64String
  .replace(/=/g, "")
  .replace(/\+/g, "-")
  .replace(/\//g, "_")

// 5. Output `token`
console.log("token:", base64StringUrlEncoded);
token: eG-FUWZjMW_sMf-IeFxDJdYRbQY

RFC 4648 - Section 5 - Base 64 Encoding with URL and Filename Safe Alphabet

You can easily adjust the number of bits of entropy and your token is more compact (in term of bits of entropy per byte) that a standard UUIDv4 representation.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .