The Why and How of MAC HTTP Cookies

When the web first started out everything was stateless — a request was made, it hit a server somewhere, and the server responded without knowing anything beyond the IP address of the request. All was good with the web. Stateless worked fine for serving up plain text documents. But slowly browser manufacturers and those building websites wanted more. They wanted to track state across requests and the HTTP cookie was born.*

HTTP cookies are simply a way to track state across multiple HTTP request-response cycles. There are many usages of cookies from the practical of session management to the more nefarious of tracking user activity across the web. This post is going to talk about a very specific subset of cookie known as the MAC or flash cookie. How they work and when you may want to use one. But first, a little cookie background…

How a Cookie Works

The cookie concept is dead simple. A server decides it wants to save the state of some client, i.e. a web browser session, so it sends a Set-Cookie HTTP response header. The client receives the header and sends back the cookie value as a request header on every subsequent request until the cookie expires.

Although cookies are simple in concept, there is nuance that can give issue. One of the biggest holes in the cookie paradigm is that clients can create, modify and delete cookies — a server may request that a cookie gets set via the Set-Cookie header, but the client can override the server’s wishes with a bit of JavaScript that alters the value set by the server.

What is a MAC

A MAC (Message Authentication Code) is a cryptographic tool to ensure a value sent by some entity has not changed. It can be thought of as checksum where the checksum function requires a secret key so only the message owner can compute it. The typical MAC workflow is:

  1. Message owner creates the message. MACs the message using the secret key only it knows. Appends the MAC to the message.
  2. Transmits the message with the MAC appended to some untrusted party.
  3. The message with the MAC is returned to the message owner at some point. A MAC is calculated on the untrusted message using the same secret key. The calculated value is compared with the MAC appended to the message. If the MACs match, the message is trusted.

This works because it is impossible for the untrusted party to calculate a new valid MAC — which is necessary when changing the value — without the private key.

Combining a MAC and a Cookie

As stated before, one of the issues with cookies from the perspective of the cookie creator (server) is that the cookie value can be changed by the client without the knowledge or consent of the server. Appending a MAC to a cookie value allows a server to determine if a value has been changed by the client when the cookie value is submitted on the next request.

The server pseudo-code to generate a MAC cookie would look like:

String cookieValue = "Om nom nom nom";
// Mac the cookie value
String macForCookieValue = Mac.generate({value: cookieValue, secret: "server-secret123"});
// Add the "Set-Cookie" header with MAC appended to value
response.setHeader({name: "Set-Cookie", value: String.template("${cookieValue};${macForCookieValue}"));

The header produced will look something like:

Set-Cookie: myCookie="Om nom nom nom;yiiS9PMRhBDdDHemtZBa3Gx0hqI"

Then on the next request the cookie value will be passed back to the server who can verify that the value has not changed by using the following pseudo-code:

// Get the value and MAC from the request
String cookieValue = request.getHeader({name: "myCookie").split(";").frist();
String macForCookieValue = request.getHeader({name: "myCookie").split(";").last();
String validMac = Mac.generate({value: cookieValue, secret: "server-secret123"});
boolean isValidMac = macForCookieValue.equals(validMac);

A common use case for a MAC cookie is to display a message on the page after a redirect — known as a flash message. Since the request is being redirected, setting the message as a query parameter will not work — the query parameter will not persist after the redirect. With this in mind, a cookie makes a lot of sense as a medium to store the message. However, there is the danger that the message could get altered on the path from creation to redirect to making it onto the page. To ensure the flash message is not altered, a MAC cookie can be used.

What About Encryption?

One of the things you may have noticed in the above example is that the MAC cookie value text is still in plain text. That is because MACs provide authentication — verifying that the server is the entity that set the value, but not confidentiality — keeping the cookie contents secret. If a cookie requires confidentiality, Authenticated Encryption (AE) should be used, which combines both authentication and encryption.

Takeaways

  • Use MACs as a way to verify data has not changed while passing through an untrusted medium. For example, a cookie value on a client (browser).
  • MACs do not provide confidentially. And encryption alone does not provide authentication. For confidentially+authentication use Authenticated Encryption (AE).

*Fun side note: The first cookie browser implementation was in Netscape Version 0.9beta. They added it so they could track whether users had already visited their website.