2

I know there are multiple libraries for managing authentication, but I have a hobby project and wanted to create a very simple authentication system. It'd set a cookie in the client's browser with a random id and then check against it in the database to get the user information.

I thought of using crypto.getRandomValues(new Uint32Array(16)).join('') for creating these cookies ids.

Question: Is this safe enough or am I making a horrible mistake? It also seems bad to me that it only uses 0-9 characters, it'd probably be much more secure if I used ASCII letters as well.


In particular, I see 2 main risks with this approach:

  1. An attacker might guess the number a specific user received (highly unlikely)
  2. An attacker might randomly pick a number based on the number generating algorythm and impersonate a random user. For example, if it's likely that number 123456... can be generated, the attacker can set a cookie with this number and, if this id is registered in the database, the attacker will be logged in as the user with that cookie id (unlikely?)

Related:
Cookie generation
Secure authentication cookie for web site

3
  • Why do you ask for JavaScript? Like, are you generating these client-side? Or is this for a Node.js thing?
    – user163495
    May 6 at 1:02
  • 1
    @MechMK1 it's a Node.js thing:) you're right, it should definitely be generated in the server
    – flen
    May 6 at 1:15
  • Ah, I understand. Back in my days, so like 12 years ago, JS used to be client-exclusive. But yeah, it seems pretty solid. CBHacking's answer explains it very well.
    – user163495
    May 6 at 10:59

2 Answers 2

2

Is this safe enough or am I making a horrible mistake?

Safe enough. Overkill, honestly. The most notable improvement I'd recommend here in particular is hashing the session token before storing it in the DB (or checking it against the DB-stored list of sessions). That way, even if an attacker gets a look at the DB, they couldn't steal somebody else's session. You should also enforce a server-side timeout for sessions, if you're going to have them time out at all.

Of course, there's a ton of other considerations that go into an authentication system (much less authorization). What credentials to use and how to verify them, how to handle loss of credentials (e.g. forgotten password), multi-factor auth, and so much more.

Also, specifically with cookies, you need to make sure your service is secure against CSRF (Cross-Site Request Forgery) attacks. There's a bunch of ways to do that but you do need to do at least one of them.

seems bad to me that it only uses 0-9 characters, it'd probably be much more secure if I used ASCII letters as well

Nope, that's actually pretty irrelevant. 16x UInt32 is 512 bits (64 bytes), which is excessively high entropy for a session token (most are in the 128-256 bits range, and every extra bit doubles the difficulty to brute-force the token). Representing it as decimal digits [0-9] isn't any less secure than representing it as hex [0-9A-F] or base64 [0-9A-Za-z./], and also isn't any more secure than representing it as octal [0-7] or even binary [0-1]. 64 bytes can be 512 binary digits, or 171 octal digits (including two bits of padding), or 155 decimal digits (again including some padding), or 128 hex digits, or 86 base64 digits (including some bits of padding, plus usually it would be further padded with two = for a total length of 88).

You see how the string gets shorter the wider the character set used? Yet they all have the exact same amount of unguessability (entropy).

Now, string concatenation of decimal values (without delimiters or padding) in particular is a bad way to handle this, because it does introduce ambiguities (simple example: the string "101234" could be formed by the numbers "101","234", or "10","1234", or "10","12","34", or... you get the idea), but it still doesn't matter. Even if we assume that the string randomly ended up only 100 digits long - less likely than correctly picking a randomly selected atom of the planet Earth - it would still ludicrously unguessable (279-332 bits of entropy, far stronger than the encryption keys used for financial communications).

2
  • Great idea about hashing the ids! But, besides ensuring it's a long hash, is there some measure I should take to avoid collisions? Maybe using a specific algorithm? Though if it's long enough, I guess it should never collide (well, at least in a hobby project). Thank you for all the good info!
    – flen
    May 6 at 1:50
  • 1
    Any modern cryptographically secure hash function would be fine. In general, the SHA2 or SHA3 families are what's currently recommended. Even a 256-bit digest is more than strong enough, though if you want to avoid losing any entropy, both families also support a 512-bit digest.
    – CBHacking
    May 6 at 11:23
1

Here is a simple html web page that uses the javascript Crypto.getRandomValues() function to create a random 32-byte hexadecimal string:

<html lang="en">
<head>
<meta charset="utf-8">
<title>Random String Generator</title>
</head>
<body>
<h3>Random String Generator</h3>

<script>
document.write(bytestohex(window.crypto.getRandomValues(new Uint8Array(32))));

function bytestohex(bytes) {
    var hexstring='', h;
    for(var i=0; i<bytes.length; i++) {
        h=bytes[i].toString(16);
        if(h.length==1) { h='0'+h; }
        hexstring+=h;
    }   
    return hexstring;
}
</script>
</body>
</html>
3
  • Thanks a lot! This shortens the string and adds in a few more characters, but is this secure enough to be a cookie id? Or would someone be able to either guess it or randomly try a value? (for example, I might not know to whom id = 123456... belongs, but I can try setting it as my cookie and impersonating someone randomly, and then having access to everything that person has)
    – flen
    May 6 at 0:42
  • 1
    You are welcome, I hope this helped. The reason why I made it 32 bytes is to make it practically impossible to crack. See security.stackexchange.com/questions/234525/… for some interesting reading on why 32 bytes should be more than enough.
    – mti2935
    May 6 at 1:02
  • 1
    It definitely did, thank you! The other answer was also very useful, good to know I'd require a second sun to break my cookie's id
    – flen
    May 6 at 1:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.