HTTP Security Headers are a seatbelt
I've written several articles on Hashnode recently about the importance of HTTP Security Headers and how so many sites lack the proper security HTTP header configurations.
In this post, I will briefly go over what security headers are and what they are not when it comes to improving the overall security posture of your website or web app.
What they are
In this article, "security headers" is referring to the HTTP response headers which your server sends to your client.
Who they protect
Security headers mainly protect your users because they control what the users browsers allow and disallow while the user is browsing on your website or using your web app. However, protecting your users also means protecting your own organization's reputation, legal liability, and ability to succeed. It's never good when a user gets defrauded by a criminal in another country due to a security vulnerability in your web service!
What type of protection do they offer?
Security headers mostly offer "fallback" protection. They are like a seatbelt - to prevent injury, a driver can just avoid all accidents by have lightening quick reflexes and being hyperaware of surroundings at all times... However, the driver wears a seatbelt because if #1 doesn't work, he/she falls back to the seatbelt for protection in the event of a collision.
Similarly, if all user inputs are properly sanitized, and data going from the server to the browser is properly sanitized, and there are no open redirects, and you have a secure connection enforced by HSTS where no MITM is easily possible, and the page runs no scripts from vulnerable outside sources... Cross-Site scripting won't be possible, so if all that is true, then it's not required to have anti-XSS protections in the HTTP security headers. However, that's like not wearing a seatbelt while driving because you think you can avoid all collisions...
HTTP security headers such as
Strict-Transport-Security offer fallback protections so that when your team slips up in 1 area, or when one of your 500 dependencies has a security bug, it is much less likely to be exploitable. For instance, the
This is mostly the case, but not always the case
There are some cases in which properly configured security headers are the primary means of preventing a specific type of attack, rather than the fallback means. One example is the use of either the
X-Frame-Options: SAMEORIGIN header or the
Content-Security-Policy: frame-ancestors self; header. These headers are used as a primary means to prevent a clickjacking aka UI redress attack. Another example is the
There are always multiple ways to prevent attacks - setting headers is one of them, but it is often the simplest and most standardized method of doing so. One issue is if you write custom code to protect against a specific type of attack, how do you ensure that your code considers all cases properly? It has a higher chance of missing an edge case and allowing the attack than time-tested protections implemented by the browser vendors.