HTTP Security Headers With Nginx
HTTP Security Headers With Nginx
HTTP Headers
HTTP is the language of the web. Clients and servers communicate with each other using HTTP. HTTP
messages can contain one or more optional headers that allow the client and the server to pass additional
information with the request or the response.
You can inspect the request/response headers within the browser by visiting a web page and opening the
browser console (Ctrl+Shift+K on Firefox, Ctrl+Shift+J on Chrome) and clicking on the Network
tab.
Note that on visiting the homepage of Attosol at http://www.attosol.com, the server responds with a 301
(Moved Permanently) status code and sets the Location header to https://www.attosol.com, forcing
the browser to make the request again using HTTPS.
Nginx
Nginx can be configured to set response headers by modifying the server blocks in the configuration files.
Here, we set the X-Content-Type-Options header, used to protect against MIME sniffing
vulnerabilities. The alwaysparameter ensures that the header is set for all responses, including internally
generated error responses.
Header Inheritance
Generally, you place the add_header directive in the top‑level s erver block. When you do this, Nginx
will ignore the headers from the parent block. Similarly, if a location includes an add_header directive
itself, it does not inherit headers from enclosing server block. When you specify a header inside a child
block, you need to re-declare all add_header directives from the parent block inside the child block again.
HSTS is a way to deal with this potential vulnerability by instructing the browser that a domain can only be
accessed using HTTPS. If the user enters or uses an HTTP link, the browser strictly upgrades the
connection to HTTPS:
On receiving the HSTS header from a website, the browser will prevent any further communication to that
website over HTTP and will use HTTPS instead. We can configure nginx to set the HSTS header on every
response using the add_header directive.
server {
listen 80;
listen [::]:80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen [::]:443 ssl ipv6only=on;
listen 443 ssl;
ssl_certificate path_to/fullchain.pem;
ssl_certificate_key path_to/privkey.pem;
include path_to/options-ssl-nginx.conf;
ssl_dhparam path_to/ssl-dhparams.pem;
root /var/www/html/your_app;
index index.html;
server_name your_domain;
location / {
try_files $uri $uri.html $uri/ =404;
}
When a browser sees this header from an HTTPS website, it “learns” that this domain must only be
accessed using HTTPS. It caches this information for the max-age period (typically 31,536,000 seconds,
equal to about 1 year). On initially testing HSTS, it is recommended to start with very small values for the
max-age timeout.
The optional includeSubDomains parameter tells the browser that the HSTS policy also applies to all
subdomains of the current domain. Check the image below and notice the Status code 307.
The previous requests follows with a regular redirect, and you can find the Strict-Transport-Security header
in the next request as follows (we have kept the age to 1 day or 86400 seconds only for demonstration
purpose):
HSTS Preload
You can only set the HSTS header over HTTPS. HSTS works with a trust-on-first-use assumption. To
eliminate this and to force HTTPS even on the very first request, you can submit your domain to a preload
list. Preload lists are hard-coded into the browsers, ensuring that even the very first request would be made
over HTTPS.
Content-Security-Policy: policy
CSP makes it possible to reduce or eliminate the vectors by which XSS can occur by specifying the
domains that the browser should consider to be valid sources of executable scripts. A CSP compatible
browser will then only run scripts loaded in source files received from those whitelisted domains.
Policy
The policy is a list of whitelisted sources for content on the website. Check out the results of setting a CSP
on a website.
default-src directive defines valid sources for fonts, images, media, scripts and styles. self matches
the scheme, port and origin of the document it is served with. The browser effectively blocked loading of all
external stylesheets and scripts.
Let's modify this directive to allow the blocked content with the new CSP.
One major feature of CSP is the granularity of the controls that it allows. To further lock down our CSP
while allowing the required content on our page, we could rewrite our policy, disallowing images/videos,
frames.
script-src, style-src are some of the directives that help define the policy with higher granularity.
Checkout this CSP Cheat Sheet to learn more about the CSP directives.
CSP Reporting
CSP can be tested in a report-only mode or deployed in production with violation reporting.
You can configure your own back-end service to handle the incoming reports. Also, report-uri.com provides
a free CSP report collection service.
server {
listen 80;
listen [::]:80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
ssl_certificate path_to/fullchain.pem;
ssl_certificate_key path_to/privkey.pem;
include path_to/options-ssl-nginx.conf;
ssl_dhparam path_to/ssl-dhparams.pem;
root /var/www/html/your_app;
index index.html;
server_name your_domain;
location / {
try_files $uri $uri.html $uri/ =404;
}
}
Other Headers
Note the 3 new headers added in the configuration file shown above.
The X-Frame-Options header can help prevent click-jacking attacks. This header indicates whether the
web page can be rendered in a <frame>.
The X-XSS-Protection header is used to ensure that the browser's XSS Protection filter is turned on.
While these headers provide protection in older browsers, implementing a strong Content-Security-Policy
covers much more ground.
Parting words
The web platform offers a wide variety of tools and techniques for security. securityheaders.io is a very
helpful tool that you can use to check if your web server is setting the headers properly. We covered
techniques to mitigate a few threats to web applications. Stay safe!