Security HTTP Headers

Posted on: July 26, 2018 by Dimitar Ivanov

Last few years a bunch of new HTTP headers were added to the web platform. The purpose of this blog post is to discuss the most critical headers from a security perspective.


This http header helps avoiding clickjacking attacks. Browser support is as follow: IE 8+, Chrome 4.1+, Firefox 3.6.9+, Opera 10.5+, Safari 4+. Posible values are:

browser refuses to display requested document in a frame
browser refuses to display requested document in a frame, in case that origin does not match
allow-from: DOMAIN
browser displays requested document in a frame only if it loaded from DOMAIN
// Raw header
X-Frame-Options: sameorigin

// How to send the response header with PHP
header("X-Frame-Options: sameorigin");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set X-Frame-Options "sameorigin"

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("X-Frame-Options", "sameorigin");
Figure 1. X-Frame-Options

Note: The Content-Security-Policy HTTP header has a frame-ancestors directive which obsoletes this header for supporting browsers.


Use this header to enable browser built-in XSS Filter. It prevent cross-site scripting attacks. X-XSS-Protection header is supported by IE 8+, Opera, Chrome, and Safari. Available directives:

disables the XSS Filter
enables the XSS Filter. If a cross-site scripting attack is detected, in order to stop the attack, the browser will sanitize the page.
1; mode=block
enables the XSS Filter. Rather than sanitize the page, when a XSS attack is detected, the browser will prevent rendering of the page.
1; report=<reporting-URI>
enables the XSS Filter. If a cross-site scripting attack is detected, the browser will sanitize the page and report the violation.
// Raw header
X-XSS-Protection: 1; mode=block

// How to send the response header with PHP
header("X-XSS-Protection: 1; mode=block");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set X-XSS-Protection "1; mode=block"

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("X-XSS-Protection", "1; mode=block");


This http header is supported by IE and Chrome, and prevents attacks based on MIME-type mismatch. The only possible value is nosniff. If your server returns X-Content-Type-Options: nosniff in the response, the browser will refuse to load the styles and scripts in case they have an incorrect MIME-type. The list with available MIME-types for styles and scripts is as follow:

  • text/css
  • application/ecmascript
  • application/javascript
  • application/x-javascript
  • text/ecmascript
  • text/javascript
  • text/jscript
  • text/x-javascript
  • text/vbs
  • text/vbscript
// Raw header
X-Content-Type-Options: nosniff

// How to send the response header with PHP
header("X-Content-Type-Options: nosniff");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("X-Content-Type-Options", "nosniff");

So if you try to load for example a HTML document as external script resource (the src attribute of HTMLScriptElement), the browser will refuse it.

Figure 1. X-Content-Type-Options


To take advantage of this security header, the current webpage must be accessed over HTTPS. In this case the Strict-Transport-Security header force secure connections to the server. This prevents losing session data stored in cookies. Also prevents users to access website in case the server's TLS certificate is not trusted. Browser support: IE 11+, Chrome 4+, Firefox 4+, Opera 12+, Safari 7+. Accepts following directives:

Required. The number of seconds that browser should force the connection over HTTPS.
Optional. If present, tells to the browser that the policy applies to current host and to all host's subdomains.
Optional. Not part of the specification.
// Raw header
Strict-Transport-Security: max-age=31536000
// or
Strict-Transport-Security: max-age=31536000; includeSubDomains

// How to send the response header with PHP
header("Strict-Transport-Security: max-age=31536000");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set Strict-Transport-Security "max-age=31536000"

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("Strict-Transport-Security", "max-age=31536000");


This header could affect your website in many ways, so be careful when using it. The configuration below allows loading scripts, XMLHttpRequest (AJAX), images and styles from same domain and nothing else. Browser support: Edge 12+, Firefox 4+, Chrome 14+, Safari 6+, Opera 15+

Few notes: IE 10 and 11 supports CSP through the X-Content-Security-Policy header; Safari 5.1 supported through the X-Webkit-CSP header.

// Raw header
Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';

// How to send the response header with PHP
header("Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set Content-Security-Policy "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';"

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("Content-Security-Policy", "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';");


The Access-Control-Allow-Origin is part of the cross-origin resource sharing specification which we discussed recently.


The Public Key Pinning Extension for HTTP (HPKP) is a security feature that tells a web client to associate a specific cryptographic public key with a certain web server to prevent man-in-the-middle attacks with forged certificates. Currently, the HPKP header is deprecated and its support was removed.


Controls the value of Referer header sent with the additional requests for resources from a web page. Firefox 36+ and Opera 15+ had a full support of the specification. Edge 12+ and Safari 7.1+ supports the older draft of the spec with never, always, origin and default values. Chrome 21+ does not support same-origin, strict-origin and strict-origin-when-cross-origin values. Valid values are as follow:

An empty string is considered to no referrer policy, i.e. referrer fallbacks to policy defined elsewhere.
Means that no referrer information is sent along the requests.
The referrer is sent to requests with better or same security (HTTP to HTTPS, HTTPS to HTTPS, HTTP to HTTP), but not less (HTTPS to HTTP). This is the default policy.
The referrer header is sent only to same-origin requests. A request is with same-origin when the URL scheme, hostname and port of the source and destination matches.
Browsers will always send the referrer header, but it will contain only the origin. The pathname and query string will be stripped-off.
The referrer header consists of only the origin and is sent to requests with better or same but not less security.
The referrer is always sent, but contain only the origin if a request is cross-origin. Otherwise, the full URL is sent.
Browsers send only the origin as a referrer to cross-origin requests and the full URL to those with same-origin, but no referrer is sent to less secure destinations.
A full URL, without parameters, is sent along both the same-origin and cross-origin requests.
// Raw header
Referrer-Policy: origin-when-cross-origin

// PHP
header("Referrer-Policy: origin-when-cross-origin");

// Apache
<IfModule mod_headers.c>
    Header set Referrer-Policy "origin-when-cross-origin"

// nginx
add_header Referrer-Policy "origin-when-cross-origin"

// Express.js
app.use(function(req, res, next) {
    res.header("Referrer-Policy", "origin-when-cross-origin");


Certificate Transparency policy means that user-agents, e.g. browsers should block an access to a website with a certificate that is not registered in public CT logs (after October 2017). Omitting the enforce directive will make it work only in report-only mode. In the other side, the report-uri directive is meaningless when used together with the enforce directive.

The time, in seconds, that the user-agent should regard the host received as an Expect-CT Host.
An optional directive that indicates the URI to which the user-agent should report Expect-CT failures.
An optional, valueless directive that, if present, signals to the user-agent to block future requests that violate the CT policy.
// Raw header
Expect-CT: max-age=7776000, enforce, report-uri=""

// PHP
header("Expect-CT: max-age=7776000, enforce");

// Apache
<IfModule mod_headers.c>
    Header set Expect-CT "max-age=7776000, enforce"

// nginx
add_header Expect-CT "max-age=7776000, enforce"

// Express.js
app.use(function(req, res, next) {
    res.header("Expect-CT", "max-age=7776000, enforce");


The Feature-Policy header gives a site owners an opportunity to enable and disable specific browser features and APIs. This is a list of currently supported features:

NB » Recently, this header was renamed to Permissions-Policy in the spec.

To control the origins use the following values:

Any origin have an access to this feature.
Only the same-origin have an access to this feature. This is the default behavior.
None origin have an access to this feature.
Only the specified origins have an access to this feature.
Feature-Policy: camera 'none'; fullscreen 'self'; geolocation *; microphone 'self'


This specification used to be named Feature Policy. This is a list of currently policy-controlled features:

Permissions-Policy: camera=(), fullscreen=self, geolocation=*, microphone=(self "")


The Clear-Site-Data header clears browser data for requested origin. The following directives are supported:

"*" (wildcard)
clear all types of data
clears browser cache
clear all browser cookies on entire domain, including subdomains
clear all DOM storage, including localStorage, sessionStorage, IndexedDB, AppCache, WebSQL, Server Workers
reload all browsing contexts
Clear-Site-Data: "cache", "cookies", "storage"


The HTTP Cross-Origin-Resource-Policy response header conveys a desire that the browser blocks no-cors cross-origin/cross-site requests to the given resource. Supported directives are:

Cross-Origin-Resource-Policy: same-site


The HTTP Cross-Origin-Embedder-Policy (COEP) response header prevents a document from loading any cross-origin resources that don't explicitly grant the document permission (using CORP or CORS). Supported directives are:

This is the default value. Allows the document to fetch cross-origin resources without giving explicit permission through the CORS protocol or the Cross-Origin-Resource-Policy header.
A document can only load resources from the same origin, or resources explicitly marked as loadable from another origin.
Cross-Origin-Embedder-Policy: require-corp


The HTTP Cross-Origin-Opener-Policy (COOP) response header allows you to ensure a top-level document does not share a browsing context group with cross-origin documents. Supported directives are:

This is the default value. Allows the document to be added to its opener's browsing context group unless the opener itself has a COOP of same-origin or same-origin-allow-popups.
Retains references to newly opened windows or tabs which either don't set COOP or which opt out of isolation by setting a COOP of unsafe-none.
Isolates the browsing context exclusively to same-origin documents. Cross-origin documents are not loaded in the same browsing context.
Cross-Origin-Opener-Policy: same-origin

Big players as Google+, Facebook, Twitter, LinkedIn use the above HTTP headers as an additional layer on a defence of their architecture. So it's strongly recommended the use of security HTTP headers to make your website safer and resist of attacks. Do you want to know how secure is your website? Let's find out with a quick scan of your server response using our Headers Inspector tool.

Make your website more secure by using the HTTP Headers for Wordpress, and never face a cross-origin issue again. Oh yes, it's FREE.
See also
Share this post

Thanks so much for reading! If you have questions about HTTP security please drop a comment below. Don't forget to share too.


Thanks to this blog entry. You solve all the query my mind about header security about most successful companies use this type of security.
Dimitar Ivanov
Thanks, Aditya. It's great to know you find my article about HTTP security useful.
Hi Dimitar,

Thanks for such expert blog post. I need to implement all these headers in one of my PHP website. Can you please let me know how I can do this? If I send response header only via apache (.htacces) then would it be sufficient ? Or I need to implement other options as well.

Dimitar Ivanov
Hi Raj,

The server has to send these headers, so there is no matter what you have used, e.g. server-side language (PHP, Ruby, Python) or server configuration file (.htaccess)
Thanks, Dimitar.

It means the examples above are showing different ways of doing this and we only need to integrate only one way.

Thanks again.
but how to use this for java script and jsp
Dimitar Ivanov
Hi Sanju,

To sent a header In JSP you can use the setHeader method:

response.setHeader("X-XSS-Protection", "1; mode=block");
response.setHeader("X-Content-Type-Options", "nosniff");
Hi Dimitar,
My application is in IIS,coldfusion,javascript ,jquery and sql server when i ran IBM app scan tool following issues reported
1. Missing "Content-Security-Policy" header
2. Missing "X-Content-Type-Options" header
3. Missing "X-XSS-Protection" header
4. Missing HTTP Strict-Transport-Security Header
Can you please let me know how to resolve in html,Javascript and iis
Hi Dimitar, thanks for the article. I have been using these headers for a while, but something completely passed me by - My apps use https and one day using fiddler I was initially surprised not to see my headers, but of course they are http. Does this mean I cannot have the same protection using https, or in some way do they still work in https?
Dimitar Ivanov
Hi @Craig,
Fiddler disabled the HTTPS decryption by default. To enable it, do following:

1. Click Tools > Fiddler Options.
2. Click the HTTPS tab. Ensure the Decrypt HTTPS traffic checkbox is checked.
Hi Dimitar, many thanks for your help. After setting Fiddler to decrypt, I can now see my security headers. Many thanks for your help. Best Regards Craig
Good article we shared it on our page
Thanks for the blog post Dimitar Ivanov. It helped me a lot.
Thanks for sharing this blog, so clear and descriptive example of each and every security http headers. It helps me a lot.
Ayub Pakzat
It was great
Enabled all options for my website
thank you
This is brilliant. I wish that I had found this page days ago.
Thank you for including clear and concise examples.
I have wasted SO much time with the other clown sites that talk about the syntax but they seem too stupid to put examples.
Spasebo very much
pascal leconte
pascal leconte June 12, 2019 at 12:57 pm
Thank you for this very complete plugin.

Just found 2 problems in http-headers.php file:
- line 927 : sprinf instead of sprintf causing an error when enabling Compression,
- Vary option does not work, as it is not implemented

I made updates in my environment. Is there a way to sens this to you ?

Dimitar Ivanov
Dimitar Ivanov June 13, 2019 at 13:46 pm

Thank you very much for the bug report.
I've just fixed those issues and released a new version.

However, if you still need to submit your fixes/improvements, please use the plugin' GitHub repository:
The use of these headers are part of the best practices to follow when we're developing an application. 'Secure headers' are designed to restrict modern browsers from encoutering vulnerabilities. Like clickjacking, XSS, MITM, etc.

Comments are closed