Secure cookie configuration
Limit access to cookies as much as possible.
Problem
Cookies often contain session identifiers or other sensitive information. Unauthorized access to cookies, therefore, can cause a host of problems, including privacy issues, ( Cross-site scripting (XSS) ) attacks, Cross-site request forgery ( CSRF ) attacks, and more.
Solution
To minimize the scope for cookie vulnerabilities on your site, limit access to cookies as much as possible. This can be done via sensible usage of the following directives of the
Set-Cookie
header:
Cookie names should be prepended with either
__Secure-
or
__Host-
to prevent cookies from being overwritten by insecure sources.
__Host-
for all cookies needed only on a specific domain (no subdomains) where
Path
is set to
/
.
__Secure-
for all other cookies sent from secure origins (
HTTPS
).
Secure
All cookies must be set with the
Secure
directive, indicating that they should only be sent over HTTPS.
HTTP Strict Transport Security
(HSTS) can also be used to prevent transmission over HTTP, but ideally
Secure
should be set on cookies as well.
HttpOnly
Cookies that don't require access from JavaScript should have the
HttpOnly
directive set to block access, such as from
Document.cookie
. It is particularly important that session identifiers don't have JavaScript access, to help prevent attacks such as CSRF.
Expires
and
Max-Age
Cookies should expire as soon as they are no longer needed. Session identifiers in particular should expire as quickly as possible.
Expires
is preferred unless you need to support IE < 8, in which case use
Max-Age
.
Expires
: Sets an absolute expiration date for a given cookie.
Max-Age
: Sets a relative expiration date for a given cookie.
Note:
Expires
has been available for longer than
Max-Age
; however,
Max-Age
is less error-prone, and takes precedence when both are set. The rationale behind this is that when you set an
Expires
date and time, they're relative to the client on which the cookie is being set. If the server is set to a different time, this could cause errors.
Domain
Cookies should only have a
Domain
set if they need to be accessible on other domains; this should be set to the most restrictive domain possible.
Cookies should be set to the most restrictive
Path
possible.
SameSite
Forbid sending cookies via cross-origin requests (for example from
<img>
elements) using
SameSite
. You should use one of the following two values:
SameSite=Strict
: Only send the cookie in same-site contexts (navigations and other requests). Cookies are omitted in same-origin contexts (e.g. navigating
a.example.com
to
b.example.com
), cross-site requests (e.g. hotlinking), and cross-site navigation (e.g. when following a link from a different web page). This is a very strict setting, but it does provide strong
CSRF
protection, so use this value if possible.
SameSite=Lax
: Send the cookie in same-site requests and when navigating
to
your website. This should be used if
Strict
is too restrictive.
Both of the above values are useful in protecting against Clickjacking attacks in cases that rely on the user being authenticated.
Note:
In theory,
SameSite=Strict
should be more useful than it is in practice. It often breaks navigations — for example, users clicking a link to a website on which they are already logged in (i.e. a valid session cookie is set) appear not to be logged in, because the browser has deliberately omitted the session cookie. The best middle ground is to use
SameSite=Strict
only on tokens where CSRF is a concern or use
SameSite=Strict
everywhere, but reload the page and do a cookie check in JavaScript if there's an indication that the user is logged in but required cookies are not being sent.
Examples
Set a session identifier cookie that is only accessible on the current host and expires when the user closes their browser:
Set-Cookie: MOZSESSIONID=980e5da39d4b472b9f504cac9; Path=/; Secure; HttpOnly
Use the __Secure-
prefix to set a session identifier for all example.org
sites, set to expire after 30 days. This cookie is not sent cross-origin, but is sent when navigating to any site from another site:
httpSet-Cookie: __Secure-MOZSESSIONID=7307d70a86bd4ab5a00499762; Max-Age=2592000; Domain=example.org; Path=/; Secure; HttpOnly; SameSite=Lax
Set a long-lived cookie for the current host, accessible by JavaScript, when the user accepts the terms of service. This cookie is sent when navigating to your site from another site, such as by clicking a link:
httpSet-Cookie: __Host-ACCEPTEDTOS=true; Expires=Fri, 31 Dec 9999 23:59:59 GMT; Path=/; Secure; SameSite=Lax
Use a session identifier for a secure (HTTPS) site. It isn't sent from cross-origin requests, nor when navigating to your site from another site. When used in conjunction with other anti-CSRF measures, this provides a very strong defense for your site against CSRF attacks:
httpSet-Cookie: __Host-BMOSESSIONID=YnVnemlsbGE=; Max-Age=2592000; Path=/; Secure; HttpOnly; SameSite=Strict