Introduction to Web Cookies
As the Hypertext Transfer Protocol (HTTP) and HTTPS are considered stateless, each HTTP request the server receives is independent and does not relate to requests that came prior to it. Cookies were created in 1994 by Lou Montulli, a web browser programmer at Netscape Communications. The idea behind cookies came from giving users shopping at an e-commerce site the ability to store their items in a virtual shopping cart.
Why Do You Need to Secure Cookies?
Web browsers primarily utilise HTTP cookies for user authentication and session persistence. Attackers can utilise the cookies in unexpected ways such as:
- Stealing cookies that contain sensitive information such as session IDs or personal information (if stored insecurely).
- Reusing stolen cookies in requests to gain access to authenticated areas and existing user sessions
- Forging cookies to gain access to authenticated areas and existing sessions
The most common attack vectors that involve that involve cookies:
- Cross-site Scripting (XSS)
- Man-in-The-Middle (MiTM)
- Cross-Site Request Forgery (CSRF)
Are Cookies Secure?
The HTTP State Management Mechanism, defined in RFC-6265 specifications details several mechanisms that can be utilised by developers to reduce the risk of accessing, re-using and forging cookies. When setting a session cookie using the ‘Set-Cookie’ response header it is important to take into account each flag and how this will impact the the overall security and usability of the session cookie and ultimately, the application.
The following are all Set-Cookie flags that can be used to improve cookie security.
Expires and Max-Age flags
The Expires and Max-Age flags define the period that cookie will be valid. The Expires indicates the maximum lifetime of the cookie as an HTTP-date timestamp (weekday, DD-MM-YYYY hh:mm:ss GMT
) whereas the Max-Age flag indicates the number of seconds until the cookie expires. A zero or negative number will expire the cookie immediately.
If both are unspecified, the cookie becomes a session cookie. Once the browser is closed the cookie will be removed from the client.
Warning: Modern web browsers have a session restore feature that will save all tabs and restore them the next time the browser is used which will also restore cookies.
In instances where both Expires
and Max-Age
are set, Max-Age
has precedence.
Secure Flag
The Secure flag instructs the cookie is to only sent via a secure HTTPS connections featuring SSL/TLS encryption and never sent in clear text. If the cookie is set with the Secure flag, any subsequent requests over HTTP resources will not contain the cookie.
The Secure flag makes the cookie more resilient to Man-In-The-Middle (MiTM) attacks, however, it does not protect the integrity of the cookie only its confidentiality. Cookies with this attribute can still be read/modified in environments where attackers have access to the machine or via JavaScript if it is not set with the HTTPOnly flag.
Note: Insecure sites (http:
) cannot set cookies with the Secure
attribute. The https:
requirements are ignored when the Secure
attribute is set by localhost
Domain Flag
The Domain flag specifies the domain for which the cookie is valid. It determines which hosts can access the cookie. By default, cookies are only sent to the domain that set them, but if the Domain flag is specified, the cookie can be accessed by that domain and its subdomains.
For example, if a cookie is set with the Domain attribute as .example.com
, the cookie will be available to www.example.com
, api.example.com
, and other subdomains of example.com
, but not to other domains such as example.net
.
It is important to note that the Domain flag cannot be set to a domain that is broader than the domain of the calling script. For instance, a cookie set by www.subdomain.example.com
cannot specify the domain as example.com
, unless it includes the leading dot (.example.com
), which would allow access by the parent domain and its subdomains.
Path Flag
The Path flag specifies the URL path for which the cookie is valid. It defines the scope of the cookie in relation to the URL, meaning that the cookie will only be sent to the server when the request URL matches the specified path or a subpath of it.
For example, if a cookie is set with the Path attribute as /admin
, the cookie will only be sent for requests to www.example.com/admin
and any subdirectories beneath it, such as www.example.com/admin/settings
. The cookie will not be sent for requests to other paths, such as www.example.com/home
.
The Path flag allows for more granular control over which pages and resources can access the cookie. By setting the path to a specific directory, you can restrict the cookie to only be sent with requests that are relevant to that part of your website, thereby reducing the risk of the cookie being accessed by less secure or unrelated parts of your site.
If the Path attribute is not specified, the cookie will be sent for all requests to the domain, regardless of the specific path.
It’s important to note that the Path flag does not offer any security guarantees in terms of cookie confidentiality or integrity. It only controls the scope of the cookie’s exposure based on the URL path.
HttpOnly Flag
The HTTPOnly flag stops the cookie from being read via JavaScript similarly to that used as part of a Cross-Site Scripting (XSS) attack. When this flag is not set the cookie can be read using client-side JavaScript such as document.cookie. In instances where an application is vulnerable to XSS, an attacker could potentially exfiltrate cookies which can be used for further attacks against the application.
Browsers can only store a limited amount of cookies for a single domain, this creates a vulnerability in some instances allowing an attacker to perform a cookie jar overflow attack by repeatedly setting cookies, deleting the original HTTPOnly cookie from memory allowing an attacker to set the same cookie without the flag. The cookie than then be exfiltrated via XSS and used by a malicious threat actor.
SameSite Flag
SameSite=Strict
: The cookie is only sent if you are currently on the site that the cookie is set for. If you are on a different site and click a link to the site that the cookie is set for, the cookie is not sent with the first request.SameSite=Lax
: The cookie is not sent for embedded content, but it is sent if you trigger top-level navigation, e.g. by clicking on a link to the site that the cookie is set for. It is sent only with safe request types that do not change state, such as GET.SameSite=None
: The cookie is sent even for embedded content.
The Effectiveness of Cookie Security
When using cookies, it’s important to remember that the original IETF specification dates back to the early days of HTML and was not designed with modern cybersecurity concerns in mind. While cookie flags can mitigate many risks, they should not be relied upon as the sole defense against cross-site scripting (XSS) attacks. Attackers may find ways to bypass these protections, for instance, by exploiting verbose debugging messages or the exposure of tools like phpinfo()
.
The most effective way to safeguard against attacks on cookies and ensure web application security is to address any vulnerabilities within the application itself. The key to identifying these vulnerabilities is through manual cookie penetration testing — an approach recommended by OWASP.