A Primer on Secure HTTP Headers
By: Timothy McLaurin
Director of Security
Implementation of HTTP security headers can be a complex and confusing topic. There are several headers that are counter-intuitive and can lead to a compromise in your security posture and have unintended consequences. Below is a list of HTTP security headers, a brief explanation of their function, and security options.
Content Security Policy
Content Security Policy (CSP) is a control implemented that only allows browsers to load content explicitly specified by the operator of the website. This control was put in place as a means to mitigate Cross-site scripting and other attacks via code injected by an attacker. Most browsers either fully or partially support CSP. CSP can be either implemented in block or report mode. Report is a good setting for testing to insure that the implementation is functioning as expected across browsers. Earlier implementations of CSP were the X-Content-Security-Policy and X-Webkit-CSP. These implementations should no longer be used as they have been deprecated and have had numerous issues.
There are several configuration options known as directives for CSP. These options can be configured via a setting in your choice of web software (nginx, apache, IIS) or via Meta tags in your HTML code. The following is a list of available options:
- default-src : "special directive that source directives will fall back to if they aren’t configured." In general this setting should always be set to insure that the default behavior of allowing all resources isn't allowed. A default-src gotcha is that not all directives inherit from default-src. Base-uri, form-action, frame-ancestors, plugin-types, report-uri, and sandbox all need to be explicitly set or will use the browser's default setting. A default-src setting of "self" is generally safe but a more locked down approach would be to set it to "none" and then explicitly state resources you want allowed.
- object-src : Define from where the site can load plugins. It specifies valid sources for the <object>, <embed>, and <applet> elements. In instances where the site tries to fetch a resource outside of the bounds of what's defined in object-src, an empty HTTP 400 response code is returned.
- style-src : Define where CSS styles can be loaded from. This includes both externally-loaded stylesheets and inline use of the <style> element and HTML style attribute. It is important to note that style-src has no impact on Extensible Stylesheet Language Transformations (XSLT). XSLT is covered by script-src directive.
- img-src : Define from where the site can load images
- media-src : Define from where the site can load video and/or audio,
- frame-src : Define from where the site can embed elements like <frame> and <iframe>
- font-src : Define from where the site can load fonts,
- connect-src : Define from which sources the site can load content using the Fetch (provides an interface for fetching resources locally and across the network), XMLHttpRequest (provides client functionality for transferring data between a client and a server), WebSocket (for creating and managing a WebSocket connection to a server), and EventSource (used to receive server-sent events) Connections
- form-action : Define valid sources that can be used as the action of HTML form elements,
- sandbox: applies restrictions site actions including preventing popups, preventing the execution of plugins and scripts, and enforcing a same-origin policy
- script-nonce : Define script execution by requiring the presence of the specified nonce on script elements,
- plugin-types: Define the set of plugins that can be invoked by the protected resource by limiting the types of resources that can be embedded,
- reflected-xss: instructs a browser to activate or deactivate any heuristics used to filter or block reflected cross-site scripting attacks, equivalent to the effects of the non-standard X-XSS-Protection header,
- report-uri: instructs the browser to report attempts to violate the Content Security Policy
This header is a feature that is supported by Internet Explorer and Chrome browsers. If malicious input is detected the browser will either remove the script or stop the page from being rendered at all according to how the header is set. Below are the valid protection settings offered by the header:
- 0 - Disables the XSS Protections offered by the browser
- 1 - Enables the XSS Protections
- 1; mode=block - Enables XSS protections and instructs the browser to block the response in the event that script has been inserted from user input, instead of sanitizing.
- 1; report=http://site.com/report - A Chrome and WebKit only directive that tells the browser to report potential XSS attacks to a single URL. Data will be POST'd to the report URL in JSON format.
By default X-XSS-Protection headers are set to 1. This may be the least secure option there is counter-intuitively. An X-XSS-Protection setting of 1 can actually inject new vulnerabilities into your website and has many examples of being bypassed. When implementing this security header the safer options are 1; mode=block and 0.
HTTP Strict Transport Security (HSTS)
HSTS is a security option that instructs the browser that it is only to interact with the website via the secure transport protocol (HTTPS). It prevents attacks that will tell the browser to communicate over clear channels when it should be encrypted. HSTS is implemented by sending the Strict-Transport-Security header over an HTTPS connection. The browser will ignore any HSTS options sent via HTTP. The server sends the Strict-Transport-Security option with a max-age value that instructs the browser to send all future requests via HTTPS over the assigned time period.
HSTS automatically turns insecure links referencing the web page to secure links and instructs browsers to refuse creating a connection if the SSL certificate has an error that could question the legitimacy of the secure connection (certificate expiration, mismatched names, etc).
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
The above example sets the max age to one year, applies HSTS to the domain and subdomains (example.com and mail.example.com), and tells the browser to use a preloaded list of domain names to insure secure connections are created prior to the browser even initiating a connection.
The X-Frame-Options header is used to indicate if a browser should use a <frame>, <iframe> or <object> to build webpages. This header is meant to be a mitigation for clickjacking attacks that trick users into clicking something that is different than what was expected. X-Frame-Options prevent content from being embedded into other sites. The available values for X-Frame-Options are:
- DENY: The Page cannot be displayed in a frame
- SAMEORIGIN: The page can only be displayed in a page from the same origin as the page itself. An origin is defined as a combination of URI, hostname, and port number
- ALLOW-FROM: The page can only be displayed in a frame in the specified URL. This option is only supported by Internet Explorer and Firefox as Chrome and Safari provide this functionality via Content Security Policies.
HTTP Public Key Pinning (HPKP)
Currently supported by Firefox and Chrome, Public Key Pins allow for hashed public key information to be stored in a browser's cache. There are hundreds of Certificate Authorities (CA) that are capable of providing certificates for websites. While unlikely it is possible for an attacker to trick a CA into issuing a certificate to a fraudulent entity. With certificate pinning, website administrators are able to instruct browsers to only trust certain CAs. Below is an example implementation of HPKP:
Max-age specifies the amount of time in seconds the browser will enforce public key pins. Public Key pins require that a primary and backup key be issued. The backup key is in case the current key need to be replaced. They key and backup keys should be created from two independent Certificate Authorities. Above are 2 base64 encoded SHA 256 hashes of the certificates to be passed to the browsers. IncludeSubdomain applies the HPKP to any of the subdomains of the site. Report-uri is used to send any validation failures to specified URI for reporting. Reports are sent in addition to terminating the connection on any detected failures.
HPKP implementation is rare throughout the internet. Its usage has been limited because it can be dangerous to implement. If keys are not managed carefully, it is possible that the website will be rendered unavailable for the duration of the max-age interval.
MIME sniffing allows browsers to guess the file type being presented to it by the server by reading bits of it. This is done when file types are not explicitly defined by the web server. An attacker can abuse this behavior by tricking the browser into misinterpreting a file type and downloading malicious content. The X-Content-Type-Options HTTP header allows you to tell the browser that is should not try to guess the file type and only use those that have been defined. This header is only currently supported by Chrome, Safari and Internet Explorer. Below is the implementation:
Cross Origin Resource Sharing (CORS)
It allows a website to utilize the resources that are hosted on domains other than itself. Websites often load resources like CSS stylesheets, images and scripts from separate domains. CORS allows for explicit definition of the sites, methods, credentials, and headers allowed across the resources. Implementation of CORS should be as restrictive as possible only allowing necessary domains and methods to operate the site. Below are the list of headers implemented by CORS:
- Access-Control-Allow-Origin: a single url/domain, wildcard (*), or null are the only accepted values. Wildcard allows any domain while null allows no domain.
- Access-Control-Allow-Credentials: allows cookies or other credentials to be passed in cross origin requests when set to true.
- Access-Control-Expose-Headers: indicates which headers are safe to expose. Example values are X-Custom-Header, content-length, etc
- Access-Control-Max-Age: header indicates how long the response can be cached
- Access-Control-Allow-Methods: indicates which HTTP methods can be used when making a request. ie: Access-Control-Allow-Methods: GET, PUT, POST, DELETE, HEAD
- Access-Control-Allow-Headers: indicates which headers that can be used when making a request. ie: Access-Control-Allow-Headers: Origin, Content-Type, Accept
- Access-Control-Request-Method: indicates which method will be used when making a request. ie: Access-Control-Request-Method: GET, PUT, POST, DELETE
- Access-Control-Request-Headers: indicates which headers that will be used when making a request. ie: Access-Control-Request-Headers: Origin, Content-Type, Accept
Public Key Pinning
Cross Origin Resource Sharing
Content Security Policy