Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a standard format for HMAC in cookies?

Given a cookie x with a value 1 ..

Set-Cookie: x=1

.. a Message Authentication Code (MAC) y is added, in this case with a | delimiter.

Set-Cookie: x=1|y

How should the data, 1, and the MAC, y, be separated? Above, a delimiter is used, but this approach fails if the data could contain the delimiter. I considered using JSON,

{ "data": 1, "mac": "y" }

Which I believe would then have to be URL-encoded?

Set-Cookie: x=%7B%22x%22%3A1%2C%22mac%22%3A%22y%22%7D

Is there a standard for the format of cookie values that contain MACs?

The calculation of the MAC, y, should be irrelevant to this question. If necessary, please assume y is calculated using OpenSSL HMAC SHA-256.

like image 373
Jared Beck Avatar asked Oct 26 '25 01:10

Jared Beck


1 Answers

If we start with the HTTP standard for cookies, we see that the syntax doesn't have any special support for message signatures. What is supported is arbitrary metadata via attributes using the extension-av syntax. So you could do something like:

Set-Cookie: x=1;myhmac=y

Or, as used in this article, simply x=1;y. In practice this is likely to work fine, but in theory it runs into the issue of collision with other metadata uses (what if the client applies some other meaning to myhmac?). This is a common problem with any system for extending a standard.

If the HMAC isn't HTTP-level metadata, then it must be stored in the content of the cookie. Your suggestion of using a data structure containing the value and the signature and then encoding it is consistent with the standard:

To maximize compatibility with user agents, servers that wish to store arbitrary data in a cookie-value SHOULD encode that data, for example, using Base64.

Base64 is certainly preferable to URL encoding, and since it has a restricted character set you could simply Base64 the value itself, and then be sure that your chosen delimiter (let's say .) won't collide with the value. So instead of encoding a JSON object you could simply do:

Set-Cookie: x=Base64(1).Base64(y)

In my experience this is probably the most common approach: using Base64 for the value and signature, separated by a delimiter of your choice. To pick an example that I'm familiar with, this is how Django handles message signing, including in cookies, using : as a delimiter.

A more general approach would be to use JSON Web Signatures (part of JSON Web Tokens), a proposed standard for handling signatures that can be used in headers. This approach is similar to the last one but includes metadata (like the algorithm used). The compact syntax is:

BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) || '.' || BASE64URL(JWS Signature)

JWT libraries are probably available in all languages. Note, though, that the generality and complexity of JWTs poses potential security risks, and many would warn you away.

like image 117
Kevin Christopher Henry Avatar answered Oct 29 '25 13:10

Kevin Christopher Henry



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!