Creating HTTP Cookies
After receiving an HTTP request, a server can send one or more Set-Cookie headers with the response. The cookie is usually stored by the browser, and then the cookie is sent with requests made to the same server inside a Cookie HTTP header. An expiration date or duration can be specified, after which the cookie is no longer sent. Additional restrictions to a specific domain and path can be set, limiting where the cookie is sent.
The Set-Cookie HTTP response header sends cookies from the server to the user agent. A simple cookie is set like this:
Set-Cookie: <cookie-name>=<cookie-value>
This shows the server sending headers to tell the client to store a pair of cookies:
HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
[page content]
Then, with every subsequent request to the server, the browser sends back all previously stored cookies to the server using the Cookie header.
GET /sample_page.html HTTP/2.0
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
The lifetime of a cookie can be defined in two ways:
For example:
Set-Cookie: id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT;
Set-Cookie: id=a3fWa; Max-Age=0
When an Expires date is set, the time and date are relative to the client the cookie is being set on, not the server.
Max-Age specifies the number of seconds until the cookie expires. A zero or negative number will expire the cookie immediately.
If both Expires
and Max-Age
are set, Max-Age
has precedence.
The following cookie is a session cookie, it was removed when the user shut down the system.
Set-Cookie: sessionId=38afes7a8
If your site authenticates users, it should regenerate and resend session cookies, even ones that already exist, whenever the user authenticates. This technique helps prevent session fixation attacks, where a third party can reuse a user's session.
Restrict access to cookies
There are a couple of ways to ensure that cookies are sent securely and are not accessed by unintended parties or scripts: the Secure attribute and the HttpOnly attribute.
A cookie with the Secure attribute is sent to the server only with an encrypted request over the HTTPS protocol, never with unsecured HTTP (except on localhost), and therefore can't easily be accessed by a man-in-the-middle attacker. Insecure sites (with http: in the URL) can't set cookies with the Secure attribute. However, do not assume that Secure prevents all access to sensitive information in cookies; for example, it can be read and modified by someone with access to the client's hard disk (or JavaScript if the HttpOnly attribute is not set).
A cookie with the HttpOnly attribute is inaccessible to the JavaScript Document.cookie API; it is sent only to the server. For example, cookies that persist server-side sessions don't need to be available to JavaScript, and should have the HttpOnly attribute. This precaution helps mitigate cross-site scripting (XSS) attacks.
Here is an example:
Set-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly
Define where cookies are sent
The Domain and Path attributes define the scope of the cookie: what URLs the cookies should be sent to.
The Domain attribute specifies which hosts are allowed to receive the cookie. If unspecified, it defaults to the same host that set the cookie, excluding subdomains. If Domain is specified, then subdomains are always included. Therefore, specifying Domain is less restrictive than omitting it. However, it can be helpful when subdomains need to share information about a user.
For example, if Domain=example.org is set, then cookies are available on subdomains like developer.example.org.
The Path
attribute indicates a URL path that must exist in the requested URL in order to send the Cookie header. The %x2F ("/") character is considered a directory separator, and subdirectories match as well.
For example, if Path=/docs is set, these paths match:
/docs
/docs/Web/
/docs/Web/HTTP
The SameSite attribute lets servers specify whether/when cookies are sent with cross-origin requests (where Site is defined by the registrable domain), which provides some protection against cross-site request forgery attacks (CSRF).
It takes three possible values: Strict, Lax, and None.
If no SameSite attribute is set then the cookie is treated as Lax.
Here is an example:
Set-Cookie: mykey=myvalue; SameSite=Strict
Note: Standard related to SameSite recently changed:
-
SameSite=Lax
is the new default if SameSite is not specified. Previously the default was that cookies were sent for all requests.
-
Cookies with SameSite=None must now also specify the Secure attribute (they require a secure context).