0

Which is safer and faster? uuid4 or crypto.randomBytes for session id ?

This is how I am generating session id at the moment:

app.use(session({
 secret: 'some long secret',
 genid: ()=>{
   return crypto.randomBytes(32).toString('hex');
 },
 cookie: {
  ...
 }
}));

But I'm afraid it will block event loop. Which is better to use? uuid4 or a crypto.randomBytes ? Performance, security and speed are important to me. Thanks in advance.

Sergei Hronov
  • 29
  • 1
  • 6

1 Answers1

0

So, uuid4 just uses crypto.randomBytes() itself:

function uuid4() {
  var rnd = crypto.randomBytes(16);
  rnd[6] = (rnd[6] & 0x0f) | 0x40;
  rnd[8] = (rnd[8] & 0x3f) | 0x80;
  rnd = rnd.toString("hex").match(/(.{8})(.{4})(.{4})(.{4})(.{12})/);
  rnd.shift();
  return rnd.join("-");
}

But, it's only generating an initial 16 byte long value and it's then modifying that. If you really want to know the performance of the two, as with all performance related questions, you will have to benchmark each and compare, but if you make them the same length, then it's unlikely you find a big difference.


Either should work fine. Both are going to put a small tax on the event loop because of the use of the synchronous version of crypto.randomBytes(), but in proper use with the session this should only get triggered when a user first arrives on your site without an existing session cookie so it is not a recurring tax on every request.

Either should be plenty secure from a session guessability point of view. When it comes to security, I tend to go with widely used and widely scrutinized libraries instead of rolling my own solution since I figure that people who know far more than I do about security have been looking at the widely used solution.

Here's a descriptive post about uuid4() with some commentary about the extremely low possibility of a collision. It also explains what the bit twiddling you see in the uuid4() code is there for.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks, from your point of view, what would you use for more security? As I understand it, when I generate the session ID, this shouldn't hinder performance much because it is only generated when the user doesn't have a cookie? – Sergei Hronov Jan 30 '21 at 17:49
  • @SergeiHronov - My second to last paragraph contains my thoughts on security. Yes, this code would only kick in when a new user arrives on your site that has no existing session cookie. – jfriend00 Jan 30 '21 at 17:51
  • I read this article: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba. On the contrary, he says that a uuid4 should be used instead of a crypto.randomBytes :), Confusion arose in my head, so I decided to ask a question here. – Sergei Hronov Jan 30 '21 at 18:09
  • @SergeiHronov - Yes, that says that if you use `crypto.randomBytes()` or any cryptographically secure random number generator, you have to use it correctly. If you don't know all the details of "using it correctly", then use the widely accepted library that does. – jfriend00 Jan 30 '21 at 18:11
  • Okay, if I don't know all the details, should I use uuid4? It: `cede869307320b7e8c3d33ca6b66d6a82f81f49d3461fee05ca605d7248ed16c` generated by crypto.randomBytes(32); just looks safer than that: `110ec58a-a0f2-4ac4-8393-c866d813b8d1` generated by uuid4 :D – Sergei Hronov Jan 30 '21 at 18:18
  • @SergeiHronov - It kind of seems like you're not reading what I'm writing. Your code is generating as 32 byte random value which becomes 64 bytes long when converted to hex. `uuid4()` is using a 16 byte random value and then sacrificing a few bits to encode version info and then attempting to make it a little more readable by inserting dashes. Either will work fine. I personally would choose `uuid4()` as what it does is way more than enough. – jfriend00 Jan 30 '21 at 18:24
  • @SergeiHronov - FYI, the default session id generator built into express-session is using `crypto.randomBytes(24)`. In my express-session projects, I don't even find a reason to replace the id generator as the built-in version seems perfectly sufficient to me to prevent collisions or guessing. – jfriend00 Jan 30 '21 at 18:25
  • Thanks, I think it's worth leaving the default ID generation method. I just need to add a check if this session id is not in the database. – Sergei Hronov Jan 30 '21 at 18:35
  • @SergeiHronov - Adding a check to see if it's in the database will likely cost you the most performance of anything we've discussed here. – jfriend00 Jan 30 '21 at 18:42
  • Yes, but if two users have the same session ID, this is a security risk. – Sergei Hronov Jan 30 '21 at 18:47
  • @SergeiHronov - Perhaps you don't understand or believe the math behind how unlikely a collision is. Perhaps reading this [How long does an ID need to be?](https://eager.io/blog/how-long-does-an-id-need-to-be/) will help. Plus in the real world where sessions expire and disappear and are no longer being used, you actually have to get a collision between two active sessions in order to create a problem. So it's even far less likely than the math states because you don't keep sessions active forever. They will age away in some fashion. – jfriend00 Jan 30 '21 at 19:12
  • If I still want to protect myself from this, can adding micro-time to the ID help me? Like: `hash(uuid4()+micro-time)` – Sergei Hronov Jan 30 '21 at 20:34
  • Don't hash a `uuid`. That likely reduces randomness. You can add a stringified version of a time onto the end if you don't care how long this thing is getting. `uuid4() + Date.now()` would enhance uniqueness since only two ids coined in the same ms could ever conflict. IMO, you're going overboard here, but do whatever makes you comfortable. – jfriend00 Jan 30 '21 at 21:38
  • Thank you for your patience!!! :) I will use `crypto.randomBytes(24).toString('hex')+Date.now();` – Sergei Hronov Jan 30 '21 at 22:24