Hi everybody! So, after some feedback about the last “quick” Quick Bites (thanks Josh!), I’ve decided to try to keep this one shorter. You know, make it an ACTUAL “Quick” bite. So, without further ado, I bring you Quick Bites Episode 2 - HTTP Security Headers and Why You NEED Them. Let’s jump in, shall we?
What are HTTP Security Headers again?
I assume that most people reading this are already familiar with HTTP headers. However, a quick refresher is always good to help put us in the right frame of mind. HTTP headers are directives sent between a web server and web client (generally a browser such as Chrome, Firefox, Microsoft Edge, etc) to regulate how that client handles the code (HTML/JavaScript/etc) of a website. Essentially, they tell the client what it’s allowed (and not allowed) to do with the code.
Below is an HTTP request to https://www.professionallyevil.com/. Note all the HTTP request headers that are sent from the browser (the headers are on lines 2-16). Bonus points if you can tell me what browser I’m using!
Below is the HTTP response from https://www.professionallyevil.com/ . See how there is an entirely different set of HTTP headers in the response (lines 2-15)? These response headers are the ones that we’re focusing on in this article. Well, not these SPECIFIC headers, but the HTTP response security headers. Ahem. Yeah, just please keep reading.
OK, now I’ve seen some HTTP headers. Why do I need them?
Why, I’m glad you asked! Some of these headers provide the browser with bits of non-security related information. Others help prevent certain types of attacks such as cross-site scripting (XSS), cross-site request forgery (CSRF), protocol downgrade attacks, and others. These headers are actually quite important, but we still see them missing during web application tests which weakens the overall security of the applications. Modern browsers are equipped with the ability to understand and work with the majority of HTTP headers, so implementing them is really a no-brainer. To start, here’s a list of some of the headers, in no particular order.
Content Security Policy
The Content-Security-Policy (CSP) header is designed to let the browser know where it can and cannot load content from, including images, scripts, and media such as audio/video. It’s particularly helpful with preventing cross-site scripting, as it defines the locations where scripts can be loaded from. Having a properly written CSP can keep an attacker from loading and running scripts from other sites, or even keep them from exploiting an inline JavaScript on your webapp.
Examples:
Content-Security-Policy: script-src 'self' frame-ancestors 'self' img-src '*'
References:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
HTTP Strict Transport Security (HSTS)
This header specifies that the browser can only access content for the webapp through the HTTPS protocol. Simple. Oh, it also specifies that the browser should load the website through HTTPS for a specific amount of time (set in seconds). Note that the max-age directive is *required*, while the includeSubDomains directive is *optional*. The header essentially prevents a browser from connecting to a webapp without encryption enabled. This helps keep man-in-the-middle attacks from downgrading traffic to plaintext HTTP.
Examples:
Strict-Transport-Security: max-age=31536000; includeSubDomains
References:
https://datatracker.ietf.org/doc/html/rfc6797
X-Frame-Options (XFO)
This header helps prevent clickjacking attacks. It tells the browser whether or not the page being loaded can be rendered within a <frame> or <iframe> HTML tag. This basically prevents an attacker from embedding a page inside of an iframe on a malicious site, which can then perform an action on the clicker’s behalf. It’s not necessarily a major security issue, because it’s rare, but it’s worth including here.
Examples:
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
X-Frame-Options: ALLOW FROM https://www.professionallyevil.com
References:
https://datatracker.ietf.org/doc/html/rfc7034
Cache-Control
Caching web pages has long been used as a way to keep web traffic to a minimum. Sometimes, there’s some really sensitive information (think credit card numbers or passwords) stored in that cache, particularly for web browsers. If an attacker can gain access to that cache, then that sensitive information can be stolen, and used for fun and profit. The Cache-Control header limits the cache that is stored by the browser, by only keeping it for a certain period of time or disabling the cache for that site altogether.
Examples:
Cache-Control: max-age=604800, must-revalidate
Cache-Control: no-store
References:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
X-Content-Type-Options
When you surf a website, your browser performs a few tasks in the background. Images, scripts, and other files are loaded and presented in the browser. The web server typically sets the MIME type with a Content-Type header, which the browser can then interpret to present. For example, an PNG image will have a MIME type of image/png, which can instruct the browser to render the PNG file. However, sometimes, these files are set incorrectly, which forces the browser to “sniff” the file to determine what it is. This is called MIME sniffing.
Attackers can use this browser behavior to trick the browser into running arbitrary code by setting a malicious script file’s Content-Type to something innocuous like text/plain or an image MIME type. However, the browser can “sniff” the file, determining the actual file type, which it can then render - in this example, the server says the script file is an image, but it’s actually JavaScript, which the browser can run. This attack is called a MIME sniffing attack.
To mitigate this, the X-Content-Type-Options security header can be added to the page forcing the browser to render the file as the Content-Type header intends, preventing MIME sniffing attacks.
Examples:
X-Content-Type-Options: nosniff
References:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
The End… ?
It's important to remember that many of these HTTP response headers provide directives to the browser's built-in security controls. So when we perform a web application penetration test, we will examine these headers to determine which browser controls were left open. This analysis hints at what attack scenarios are more likely to succeed against the web application. With that being said, there are several other HTTP security headers that can be implemented, but what and how they’re used is left as an exercise for the reader. If you have any questions, check out the References section of each header, or you can simply reach out to us - we’re happy to help.