What are security headers and how do they protect your site?
- Literally…WTF is a security header?
- What do they really protect anyway? (servers? sites? users?)
- What do they do?
- How do you use them?
- Which ones should you actually worry about?
I’ll explain in technical as well as non-technical terms.
1. Why this guide exists
This guide exists for naive clients arguing with their devs over silly pages scores and “security tests”.
If your dev sent you this…it’s because you don’t know any better and you need to stop being that clown arguing with their doctor based off shit they read online.
Many “security headers” recommendations out there are not important and/or not recommended for your site. They can break functions if you’re not careful. Not only that but your site not fulfilling every check mark doesn’t mean it’s insecure. Security tests nowadays are very much like those page score test scores (Core Web Vitals, GTmetrix, etc.) And similarly…just because those sites give you a less-than-perfect score or one failing metric doesn’t necessarily mean your site is slow or poorly-built.
And last but not least, if you’re gonna argue with your dev (who knows more than you), then you better school yourself and know what you’re talking about.
“But isn’t security important?”
Of course, it is. But real server security is based proper server hardening, security protocols, network and WAF firewalls. Website security is based on good coding, and general security precautions.
And where does security headers fit in the grand scheme of overall website and web-server security?
…most of them are not really that important. They’re simple checklist type tasks that make very little impact on your site security.
2. How do Security Headers work?
Before we even talk about security headers, you must understand that they’re simply HTTP headers and to know what HTTP headers do. (Yes, do read that fucken guide or you’ll be completely lost for this guide.)
Also note that security headers are to provide security to your website visitors, NOT your web-server or your website. To secure your web-server or website, you’d be doing other things (like server firewalls or WordPress application security).
“Security headers” are basically HTTP response headers that are sent out with the webpage and tell browsers how to display (or engage with) the content.
The “security” that they provide (to visitors) is by telling the browser to limit how the webpage is displayed or engage with.
Examples of things a security header can restrict:
- Don’t show content (or display a warning) if the request is sent via
- Don’t show content or load a request if it’s sent from an external url (different from the original url). Such as your user is loading
https://yoursite.com/yourpagebut your page has external asset requests like
https://othersite.com/sneakyscript.js. In this case, the browser won’t load that external request because your HTTP response header told it not to.
- Don’t allow the browser to use the computer’s microphone or camera.
So again…in the event that your website is ever hacked, security headers basically protect your users (and their browsers) from inadvertently compromising themselves or executing malicious scripts/commands. Security headers do NOT protect your website or web-server from being hacked.
How security headers are applied (or configured) to your website:
- Security headers are applied differently depending on your web-server (Apache/LiteSpeed vs NGINX).
- Basically…Apache/LiteSpeed allows global server-wide configuration as well individual overrides for each site (via .htaccess). Whereas NGINX only has the main global Nginx configuration file. Global config files are only accessible to the server-admin or if you have full server access.
- Nowadays security headers are automated by your webhost. But you may (or may not) have the ability to customize them further.
3. Real-world examples of security headers (and my opinions)
Here’s more or less how I feel about each one of them (and WHY). Of course…you’re welcome to do whatever you want, and go against my recommendations. I’m not here to argue. But please, don’t be a PITA client to your dev.
NOTE: all my examples below are for Apache/LiteSpeed servers (with .htaccess). If you’re on NGINX server, you’ll have to look up its equivalent…but thing is NGINX doesn’t allow configuration on the site level, it only has the main server configuration and most users won’t have access to the NGINX configuration file anyway.
Default Content Security Policy (CSP)
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:;" always;
- Above was just an example snippet (don’t not blindly use for your site).
- The CSP header tells browsers which resources, and from which domains they are allowed to load.
- For example, your CSP header might specify all requests must be loading from your domain. Or that CSS and JS requests can only be loaded from your domain but not others.
- This header must be custom-configured to your site needs or else it almost always breaks WordPress site functionality, even brand new installs! For example if you have special request types, or need to allow other domains (like for CDN or 3rd-party services)…then you must specify that in your CSP header. Otherwise, certain elements of your site may not load properly.
- Recommended reading for more info on CSP.
HTTP Strict Transport Security (HSTS)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- The HSTS header tells browsers to always connect to your site using HTTPS. This prevents MITM attacks or attacks targeting insecure HTTP connections.
- Possible drawbacks? – if for any reason there is ever a lapse in your SSL certificate renewal or messy migration, your site will be completely blocked from access. (There is no browser “Advanced – proceed anyway” link.) For this reason, I personally hate HSTS security and feel it’s potentially a lot of problems.
Default Referrer Policy
Referrer-Policy no-referrer, strict-origin-when-cross-origin;
- Sets your site domain as the “referrer” in the request header when clicking outbound links from your site. This is less about security and more about following GDPR regulations.
- Read more about Referrer Policy security header.
X-Frame Options: SAMEORIGIN or DENY
SAMEORIGINprevents your site from loading frames or content from other domains. So hackers cannot load junk (from another site) into your site.
DENY(instead of “SAMEORIGIN”) blocks your website from being embedded elsewhere. So others can’t fake your content and steal your clicks (“clickjacking”).
- You can lose functionality with these headers, or certain pages may not work. Test it!
- You cannot (should not) use both SAMEORIGIN & DENY. Pick just one.
X-XSS-Protection "1; mode=block" always;
- XSS (or X-XSS) security header tells your the browser to block any requests containing malicious scripts.
- Any lost functionality? This one is pretty safe to use and doesn’t (shouldn’t) break any functionality.
Default Permissions Policy
Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()";
- Above snippet is only an example!
- The Permissions Policy header decides what browser features the website can use on its own page or in embedded content. Example of browser features are: geolocation, video-autoplay, encrypted-media decoding, user’s camera/microphone, fullscreen, etc.
- Any drawbacks? Kind of a pain to granularly block every nuanced setting. I’d say you can safely ignore this.
- To enable Permissions Policy header – enable in your .htaccess or NGINX config and customize it for your needs. An easier (less technical) method is using Really Simple SSL plugin (PAID version) but I really hate slowing down your site with more plugins for these tiny things.
- Customize your permissions policy with this Permissions Policy generator.
- The X-Content-Type-Options header stops the browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. MIME-sniffing is used by hackers who disguise backdoor files under another content-type/extension and then try to request/run it from the browser.
- Safe to use and doesn’t do too much.
Other server configs for security (but are not actually HTTP headers)
For many people, “security headers” are just bits of code you stick into the htaccess file. And I totally get why it seems that way. In reality, they are configuration info that your web-server processes and then alters the server response before replying to browser requests.
However, because since you’re already in htaccess…many security guides will suggest you to do other things as well (that are technically not HTML headers) but still help with security:
- Blocking XML-RPC protocol – this is security for your web server (not your users). Prevents DDOS attacks on your WordPress XML-RPC protocol…by restricting access to it. Of course, you don’t block it if your site uses XML-RPC.
- WAF firewall (like the 7G WAF) – a list of rules that protects your server from many DDOS attacks on network layer 7 against this site.
4. Where to see your website HTTP response headers
To see your security headers in browser developer tools:
- Right-click anywhere on your page and click Inspect, reload page and then go to Network tab then Headers tab, and scroll down.
- In the image above, you can see all the security headers I enabled in the Response Headers section.
- Your site headers may appear different.
You can also see notices about your security header in (free) online security tests:
- https://sitecheck.sucuri.net/ (simpler)
- https://www.immuniweb.com/websec/ (more detailed)
- Again, I take these with a grain of salt.
5. What’s the grand takeaway regarding security headers?
- Don’t be an annoying punkass client arguing with your dev about silly security headers (that don’t apply to you).
- Don’t blindly enable security headers without knowing how they affect your site. (YOU WILL BREAK SHIT IF YOU DO.)
- Don’t assume your site needs every XYZ security header because some fancy-looking online security test said so.
- FOR DEVS – Don’t argue with clients either. School them or fire them (or both). Today, they challenge you on security headers…tomorrow, it’ll be on speed recommendations…next week, something else. Don’t even waste your time.