简体   繁体   中英

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 .

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM