Blog / security monday
What security headers do, and how to add them
Security headers tell a browser how to treat your pages. Here are the ones worth setting on a small site, and how to add them on a cPanel account.
Security headers are short instructions your server sends with every page, telling the browser what it may and may not do with that page. They cost nothing and they do not slow a site down. Most of the small sites we look at send none of them. This week's Security Monday is one file and about ten minutes.
What a header actually does
When someone loads your site, the server sends the page plus a dozen or so lines of metadata. Most of that is housekeeping: content type, cache rules, compression. A few lines can be security rules instead: do not let other sites load my pages inside a frame, do not guess at file types, do not hand my URLs to third parties. The browser enforces them, not your site, so you close off a category of browser-side trickery without editing a theme or a line of PHP.
It also means headers protect your visitors more than they protect your server. No header patches an out-of-date plugin, and none stop someone logging in with a password stolen off a staff laptop. We cover the parts that do protect the server in WordPress security basics.
The four worth setting on nearly any site
These are safe on a normal brochure, blog or shop site, and they are what the OWASP guidance recommends:
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()
nosniff stops the browser second-guessing what a file is, so an upload that claims to be an image is never run as a script. It assumes correct content types from the server, which cPanel sends by default.
X-Frame-Options: SAMEORIGIN means only your own site can put your pages in a frame, which shuts down clickjacking: an attacker loading your admin or checkout in an invisible frame over their own page. Use DENY if nothing on your site frames your own pages. The modern equivalent is the frame-ancestors rule in a content security policy, though the older header still covers browsers that do not support it.
Referrer-Policy controls how much of your URL gets passed along when a visitor clicks out to another site. Current browsers already behave this way by default; set it anyway so you are not relying on a default that might change.
Permissions-Policy turns off browser features you never use. If your site has no map and no video call, switching off location, camera and microphone costs you nothing and removes them as an attack surface.
One header to leave alone: X-XSS-Protection. It is deprecated and non-standard, and Mozilla's documentation warns it can introduce problems on sites that were otherwise safe. If a tutorial or a plugin is still adding it, take it out.
HSTS, where you want to go slowly
Strict-Transport-Security tells browsers to only ever reach your domain over HTTPS, which kills a class of downgrade and interception attacks. It is the one header that can bite. A browser that has seen it will refuse plain HTTP to your domain for the full lifetime you set, so if your certificate lapses or a subdomain has no HTTPS, visitors see an error page they cannot click past.
So test first. Check that every hostname you use (the bare domain, www, mail, any subdomain) works over HTTPS, then start with a short lifetime like max-age=86400 and raise it after a quiet week. Only add includeSubDomains once you are certain about every subdomain, and leave preload alone unless you have read what it commits you to, because getting off that list is slow. Free certificates on our plans renew on their own, so the usual trigger for trouble here is a subdomain someone set up and forgot. More on certificates in what SSL actually protects.
Content-Security-Policy is the hard one
CSP is the most powerful header and the likeliest to break your site. It lists exactly where scripts, styles, fonts and images may load from, and a typical WordPress install pulls from more places than its owner expects: a page builder, analytics, a font service, an embedded video, inline scripts from several plugins. Get it wrong and the site looks fine to you from cache while a visitor sees an unstyled page. If you want CSP, run it in report-only mode first so violations are logged instead of blocked, then tighten it over weeks. On a small site the headers above get you most of the benefit for a fraction of the work.
Putting them on a cPanel account
On an Apache or LiteSpeed server, which is what every shared hosting account here runs, this goes in the .htaccess file in public_html. Open File Manager in cPanel, download a copy of the existing file first, then add this above the WordPress block:
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
</IfModule>
Reload the site. If you get a 500 error, put the old file back and send us the version you tried. Then confirm the headers arrived: in your browser's developer tools, open the Network tab, click the first request and read the response headers. The usual surprise is a header appearing twice, once from .htaccess and once from a security plugin that was already setting it. Pick one place and remove the other.
If you are not sure which headers your site sends today, or a change produced an error page, open a ticket with our support team and we will read the response headers from the server side and tell you what is in place.