Cross-site scripting (XSS) attacks are often aimed at stealing session cookies. In such an attack, the cookie value is accessed by a client-side script using JavaScript (document.cookie
). However, in everyday use, web applications rarely need to access cookies via JavaScript. Therefore, a method of protecting cookies from such theft was devised: a flag that tells the web browser that the cookie can only be accessed through HTTP – the HttpOnly flag.
The HttpOnly flag is not new. It was first implemented in Microsoft Internet Explorer 6 SP1 in 2002 to protect against sensitive information theft. Currently, every major browser supports HttpOnly cookies. Only some niche mobile browsers may potentially ignore this flag – see the whole list of supported browsers on the Can I Use site.
How Does HttpOnly Work?
The HttpOnly attribute is an optional attribute of the Set-Cookie HTTP response header that is being sent by the web server along with the web page to the web browser in an HTTP response. Here is an example of setting a session cookie using the Set-Cookie header:
HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: sessionid=QmFieWxvbiA1
The session cookie above is not protected and can be stolen in an XSS attack. However, if the session cookie is set as follows, it is protected from being accessed using JavaScript:
Set-Cookie: sessionid=QmFieWxvbiA1; HttpOnly
How to Set HttpOnly Server-Side?
All modern back-end languages and environments support setting the HttpOnly flag. Here is an example of how you can do this in PHP using the setcookie function:
setcookie("sessionid", "QmFieWxvbiA1", ['httponly' => true]);
The last value (true) represents setting the HttpOnly attribute.
Other Flags For Secure Cookies
The HttpOnly flag is not the only cookie security flag that you can use to protect your cookies. Here are two more that can be useful.
The Secure Flag
The Secure flag is used to declare that the cookie may only be transmitted using a secure connection (SSL/HTTPS). If this cookie is set, the browser will never send the cookie if the connection is HTTP. This flag prevents cookie theft via man-in-the-middle attacks.
Note that this flag can only be set during an HTTPS connection. If it is set during an HTTP connection, the browser ignores it.
Example:
Set-Cookie: sessionid=QmFieWxvbiA1; HttpOnly; Secure
Example of setting the above cookie in PHP:
setcookie("sessionid", "QmFieWxvbiA1", ['httponly' => true, 'secure' => true]);
The SameSite Flag
The SameSite flag is used to declare when web browsers should send the cookie, depending on how a visitor interacts with the site that set the cookie. This flag is used to help protect against cross-site request forgery (CSRF) attacks.
The SameSite attribute may have one of the following values:
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 you click a link to a 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 click on a link to a site that the cookie is set for. It is sent only with safe request types that do not change state, for example, GET.SameSite=None
: The cookie is sent even for embedded content.
Different browsers behave differently by default when the SameSite attribute is not set. For example, in 2019 the Google Chrome browser changed its default behavior for SameSite cookies.
Example:
Set-Cookie: sessionid=QmFieWxvbiA1; HttpOnly; Secure; SameSite=Strict
Example of setting the above cookie in PHP:
setcookie("sessionid", "QmFieWxvbiA1", ['httponly' => true, 'secure' => true, 'samesite'=>'Strict']);
Are Cookie Flags Enough against XSS?
Even though cookie flags are effective for many attacks, they cannot be used as a remedy for cross-site scripting. Attackers may devise ways to circumvent limitations. For example, perform cross-site tracing (CST) attacks, and steal even cookies protected by flags like HttpOnly.
The only effective way to protect against cross-site scripting is to find such vulnerabilities in the application and eliminate them at the source. And the only effective way to find such vulnerabilities is by performing manual penetration testing and/or using an automated vulnerability scanner.
Get the latest content on web security
in your inbox each week.