152

I am trying to figure out what "signed cookies" actually are. There isn't much on the net, and if I try this:

app.use(express.cookieParser('A secret'));

But still... Cookies are still 100% normal on the browser, and I don't really know what "signed" is here (I was sort of hoping to "see" some weirdness on the client, something like the data encrypted using "A secret" as salt?)

The documentation says (https://github.com/expressjs/cookie-parser):

Parse Cookie header and populate req.cookies with an object keyed by the cookie names. Optionally you may enabled signed cookie support by passing a secret string, which assigns req.secret so it may be used by other middleware.

Does anybody know?

Merc.

Merc
  • 16,277
  • 18
  • 79
  • 122
  • 1
    It should be noted that signing a cookie isn't strictly necessary if the entropy of the cookie value (i.e. the session id) is already high, and comparable to the entropy of the signature itself (256 bit in case of HMAC SHA256). This is well explained [here](https://security.stackexchange.com/questions/89537/signing-hmac-cookie-identifier) and [there](https://security.stackexchange.com/questions/213208/why-sign-session-cookies). – bluenote10 Feb 21 '21 at 16:52

4 Answers4

176

The cookie will still be visible, but it has a signature, so it can detect if the client modified the cookie.

It works by creating a HMAC of the value (current cookie), and base64 encoded it. When the cookie gets read, it recalculates the signature and makes sure that it matches the signature attached to it.

If it does not match, then it will give an error.

If you want to hide the contents of the cookie as well, you should encrypt it instead (or just stores it in the server side session). I'm not sure if there is middleware for that already out there or not.

Edit

And to create a signed cookie you would use

res.cookie('name', 'value', {signed: true})

And to access a signed cookie use the signedCookies object of req:

req.signedCookies['name']
Matt
  • 23,363
  • 39
  • 111
  • 152
staackuser2
  • 12,172
  • 4
  • 42
  • 40
  • 1
    Thanks! But... I am not seeing the signature appended to the cookie at the moment. That is, in the client the cookie is there without a signature. Is there something I need to do to enable the cookie signing, other than including the secret message in `express.cookieParser()` ? – Merc Aug 10 '12 at 08:42
  • Hang on... I am setting the cookies with `res.cookie('somethingElseAgainAndAgain', 'signed? Maybe' );` but... I doubt that's signing it! The cookieParser() middleware is there ready to parse signed cookies, but I am definitely not doing the setting right... do I have to sign them manually...? – Merc Aug 10 '12 at 08:50
  • That would be all that is needed, perhaps your cookie is from before you added the secret? Try removing the cookie to see if that kicks it into gear. – staackuser2 Aug 10 '12 at 08:51
  • Ahh, use `req.signedCookies` instead of `req.cookies` – staackuser2 Aug 10 '12 at 08:54
  • (Does my question deserve an upvote? I think it's a good one...) – Merc Aug 10 '12 at 08:54
  • req.signedCookies is to read cookies in the response... what I need is something that _sets_ the cookies with a signature at the end, I believe... – Merc Aug 10 '12 at 08:58
  • 6
    It was: `(res.cookie(name, value, { signed: true }))` . Reporting the missing "detail" from the documentation... – Merc Aug 10 '12 at 09:03
  • Alright, `res.cookie` is right, sorry I misread your original comment. – staackuser2 Aug 10 '12 at 09:04
  • @emostar thanks for this answer. I still wonder though: why is this step necessary? You can still hijack the session. Is this just to prevent the client from running through all possible session ids – enyo May 31 '13 at 16:04
  • 9
    Hijacking a session is something different... that is user B taking the identity of user A. Signed cookies are just a way to verify that the contents of the cookie have not been changed by the user, so the contents can be trusted. – staackuser2 Jul 06 '13 at 12:12
  • 17
    Worth mentioning `If it does not match, then it will give an error.` Not an *error*. Just the request.signedCookie for that key *isn't set* . So more like *ignored* – basarat Jun 08 '14 at 03:27
  • @emostar sorry to bother you but how can I check the value ? take a look at http://stackoverflow.com/questions/27548480/node-express-cookie-parser-signedcookies-how-get-the-the-real-value usually you set a cookie and then you check both if is it exists and if it is equal to a data value but in this case it seems quite useless mmmm may be I miss something ... – Whisher Dec 18 '14 at 22:09
  • Mozilla has a nice middleware for encrypted cookies: https://github.com/mozilla/node-client-sessions – sebilasse Nov 12 '15 at 10:00
  • What's the benefit to create a separate signature cookie rather than to create an encrypted one? – LCB Aug 29 '18 at 13:29
  • @LCB A signed cookie has the value accessible on the client side. An encrypted cookie should only be decrypted on the server side. In general, if you don't mind the clients being able to see the contents of the cookie, a signed cookie is secure enough. – staackuser2 Jul 20 '20 at 03:55
  • Is the signature stored in server-side memory? If it is, does that mean that a server restart will invalidate all signed cookies? – undefined Dec 19 '21 at 10:49
28

Yup like emostar mentions it's simply to ensure that a value has not been tampered with. It's placed in a different object (req.signedCookies) to differentiate between the two, allowing the developer to show intent. If they were stored in req.cookies along with the others someone could simply craft an unsigned cookie of the same name, defeating the whole purpose of them.

TJ Holowaychuk
  • 336
  • 2
  • 2
12

I have been searching pretty extensive for a good answer to this... And looking at the source code of cookie-signature, that is used by cookie-parser to sign the signed cookies have given me a better understanding of what a signed cookie is.

val is of course the value of the cookie, and secret is the string you add as option to cookie-parser

https://github.com/visionmedia/node-cookie-signature/blob/master/index.js#L16

Anders Östman
  • 3,702
  • 4
  • 26
  • 48
  • 3
    Here's a preserved canonical link: https://github.com/tj/node-cookie-signature/blob/60f3be29232145e445aada51d520d370b0a52161/index.js#L16 –  Nov 25 '14 at 18:55
  • Reading the code was indeed a much better explanation. Thanks! –  Nov 25 '14 at 18:56
2

I used cookie-parser 1.4.4 version.

I could add signed cookies and signed cookie encrypted in browser, If i try to edit signed cookie using editThisCookie (chrome plugin) then cookie-parser detect external change and then set false as value.

response.cookie('userId',401,{signed: true})

Response header in browser,appear as

Set-Cookie: empId=s%3A101.US2oSV4TSvfkvvEQ5fj1sXsjj8rNxx2ph4VdHNTuKX8; Path=/

Get signed cookie

request.signedCookies

https://gist.github.com/dineshbalaji/607d166f0240f932a5cb02099b0ece4c

Dinesh
  • 51
  • 1
  • 4