security-headers: NGINX module for sending security headers
Debian/Ubuntu installation
These docs apply to the APT package nginx-module-security-headers provided by the GetPageSpeed Extras repository.
- Configure the APT repository as described in APT repository setup.
- Install the module:
sudo apt-get update
sudo apt-get install nginx-module-security-headers
Show suites and architectures
| Distro | Suite | Component | Architectures |
|----------|-------------------|-------------|-----------------|
| debian | bookworm | main | amd64, arm64 |
| debian | bookworm-mainline | main | amd64, arm64 |
| debian | trixie | main | amd64, arm64 |
| debian | trixie-mainline | main | amd64, arm64 |
| ubuntu | focal | main | amd64, arm64 |
| ubuntu | focal-mainline | main | amd64, arm64 |
| ubuntu | jammy | main | amd64, arm64 |
| ubuntu | jammy-mainline | main | amd64, arm64 |
| ubuntu | noble | main | amd64, arm64 |
| ubuntu | noble-mainline | main | amd64, arm64 |
This NGINX module adds security headers and removes insecure headers, the right way (c).
Synopsis
http {
security_headers on;
...
}
Running curl -IL https://example.com/ will yield the added security headers:
HTTP/1.1 200 OK Server: nginx Date: Tue, 21 May 2019 16:15:46 GMT Content-Type: text/html; charset=UTF-8 Vary: Accept-Encoding Accept-Ranges: bytes Connection: keep-alive X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff X-XSS-Protection: 0 Referrer-Policy: strict-origin-when-cross-origin Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
In general, the module features sending security HTTP headers in a way that better conforms to the standards.
For instance, Strict-Transport-Security header should not be sent for plain HTTP requests.
The module follows this recommendation.
Important note on Strict-Transport-Security
The module adds several security headers, including Strinct-Transport-Security.
Note that preload is sent in the value of this header, by default.
This means Chrome may and will include your websites to its preload list of domains which are HTTPS only.
It is usually what you want anyway, but bear in mind that in some edge cases you want to access a subdomain via plan unencrypted connection.
If you absolutely sure that all your domains and subdomains used with the module will ever primarily operate on HTTPs, proceed without any extra step.
If you are not sure if you have or will have a need to access your websites or any of its subdomains over
plain insecure HTTP protocol, ensure security_headers_hsts_preload off; in your config before you ever
start NGINX with the module to avoid having your domain preloaded by Chrome.
Key Features
- Plug-n-Play: the default set of security headers can be enabled with
security_headers on;in your NGINX configuration - Sends HTML-only security headers for relevant types only, not sending for others, e.g.
X-Frame-Optionsis useless for CSS - Plays well with conditional
GETrequests: the security headers are not included there unnecessarily - Does not suffer the
add_headerdirective's pitfalls - Hides
X-Powered-Byand other headers which often leak software version information - Hides
Serverheader altogether, not just the version information
Configuration directives
security_headers
- syntax:
security_headers on | off - default:
off - context:
http,server,location
Enables or disables applying security headers. The default set includes:
X-Frame-Options: SAMEORIGINX-XSS-Protection: 0Referrer-Policy: strict-origin-when-cross-originX-Content-Type-Options: nosniff
The values of these headers (or their inclusion) can be controlled with other security_headers_* directives below.
hide_server_tokens
- syntax:
hide_server_tokens on | off - default:
off - context:
http,server,location
Enables hiding headers which leak software information:
ServerX-Powered-ByX-Page-SpeedX-Varnish
It's worth noting that some of those headers bear functional use, e.g. X-Page-Speed docs mention:
... it is used to prevent infinite loops and unnecessary rewrites when PageSpeed fetches resources from an origin that also uses PageSpeed
So it's best to specify hide_server_tokens on; in a front-facing NGINX instances, e.g.
the one being accessed by actual browsers, and not the ones consumed by Varnish or other software.
In most cases you will be just fine with security_headers on; and hide_server_tokens on;, without any adjustments.
For fine-tuning, use the header-specific directives below.
A special value omit disables sending a particular header by the module (useful if you want to let your backend app to send it).
security_headers_xss
- syntax:
security_headers_xss off | on | block | omit - default:
off - context:
http,server,location
Controls X-XSS-Protection header.
Special omit value will disable sending the header by the module.
The off value is for disabling XSS protection: X-XSS-Protection: 0.
This is the default because
modern browsers do not support it and where it is
supported, it introduces vulnerabilities.
security_headers_frame
- syntax:
security_headers_frame sameorigin | deny | omit - default:
sameorigin - context:
http,server,location
Controls inclusion and value of X-Frame-Options header.
Special omit value will disable sending the header by the module.
security_headers_referrer_policy
- syntax:
security_headers_referrer_policy no-referrer | no-referrer-when-downgrade | same-origin | origin | strict-origin | origin-when-cross-origin | strict-origin-when-cross-origin | unsafe-url | omit - default:
strict-origin-when-cross-origin - context:
http,server,location
Controls inclusion and value of Referrer-Policy header.
Special omit value will disable sending the header by the module.