How to add security headers to your site
A handful of response headers close off entire categories of attack for very little effort. Here is what each does and how to add them.
Response headers are instructions your server sends alongside every page, telling the browser how to handle it. A small set of security-related headers between them close off several categories of attack for the cost of a few lines of configuration — no code changes, no ongoing maintenance, and no effect on how the site looks or performs.
Where these headers go
On the great majority of hosting accounts, headers are added through the .htaccess file in your site's root folder, using Apache's mod_headers module. Add the lines below, then reload the site and check they are actually present using your browser's developer tools — the network tab shows the response headers for any page you load.
Add a single header, save, and reload the site before adding the next. If something breaks, you will know immediately which line caused it, rather than having to remove several at once to find out.
Strict-Transport-Security
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Tells the browser to only ever use HTTPS for this domain from now on, without needing to be redirected each time. This assumes HTTPS is already working reliably across the whole domain — see what HSTS is before turning this on, since it is the one header on this list that actively locks visitors out of HTTP once set.
X-Content-Type-Options
Header always set X-Content-Type-Options "nosniff"
Stops the browser guessing the type of a file based on its content rather than trusting the type your server declared. Without this, a browser that decides an uploaded file "looks like" a script, regardless of what it was actually meant to be, may try to execute it as one. This header is low-risk to add on virtually any site and has no legitimate reason to cause a problem.
X-Frame-Options
Header always set X-Frame-Options "SAMEORIGIN"
Controls whether your pages can be loaded inside a frame on another site. SAMEORIGIN allows your own pages to frame each other but blocks any other domain from embedding your pages inside their own, which is the standard defence against clickjacking — a page from another site invisibly overlaying your page's buttons and links underneath its own content so a visitor clicks something they cannot actually see.
Referrer-Policy
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Controls how much information about the page a visitor was just on gets passed along when they click a link to somewhere else. The setting above sends the full address for links within your own site, but only the domain — not the full path — when a visitor leaves for another site, which avoids leaking page paths, search terms embedded in a URL, or other detail an outside site has no need to see.
Content-Security-Policy
The most powerful header on this list, and the one that needs the most care. It tells the browser exactly which sources are allowed to supply scripts, styles, images and other content for your pages, and blocks anything from a source not on the list — including a script an attacker managed to inject into the page, which is one of the more effective defences against that class of attack.
Header always set Content-Security-Policy "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self'"
This starting point allows content only from your own domain. Real sites almost always need to add specific exceptions — a payment provider's script, a font service, an embedded video player — and each needs adding explicitly to the relevant directive, or the browser blocks it along with everything else not on the list.
Using Content-Security-Policy-Report-Only instead of Content-Security-Policy makes the browser report what it would have blocked, via the console, without actually blocking anything. Run in this mode while you build the correct list of allowed sources, then switch to the enforcing header once nothing legitimate is being flagged.
Checking what is actually being sent
Do not assume a header is working because you saved the file. Load the site, open developer tools, select the main document request, and check the response headers listed there. This confirms the exact text your server is sending, which is the only reliable way to catch a typo in the header name or a syntax error that caused the line to be silently ignored.
What headers do not replace
These headers reduce specific, well-understood categories of attack, but they are not a substitute for keeping software updated, using strong unique passwords, taking regular backups, and setting correct file permissions — covered in how to set safe file permissions. Think of headers as one layer among several, closing gaps that the rest of your setup cannot close on its own, rather than a complete security measure by themselves.
Frequently asked questions
Will adding these headers break my site?
Content-Security-Policy is the one most likely to, if it is set too strictly for a site that loads scripts or styles from several different sources. Add it last, test thoroughly, and consider a report-only version first so you can see what it would have blocked before it actually blocks anything.
Do I need all of these headers?
No single header is mandatory, and each protects against a specific, different problem. Strict-Transport-Security and X-Content-Type-Options are low-risk to add on almost any site; Content-Security-Policy needs more care and testing because it can be strict enough to block legitimate resources if configured carelessly.
Related reading
A header that tells browsers to never even attempt the insecure version of your site again, closing a gap a redirect alone leaves open.
How to force HTTPS on your websiteA certificate being installed does not redirect anyone by itself. Here is the rule that sends every visitor to the secure version automatically.
How to fix mixed content warningsA secure page quietly loading an image, script or stylesheet over plain HTTP. Here is how to find every instance and fix it properly.
How to set safe file permissionsThe two numbers that cover almost every case on a website: 755 for folders, 644 for files, and why 777 always creates a worse problem.