As part of our Alexa Top 1 Million Security Headers post series, it is not uncommon to have to go back and re-read specifications to determine which header values are valid. While there are numerous sites that detail the various headers and what they do, there isn't a central place that gives developers the information necessary to identify common mis-configurations and methods of testing if the security headers are set correctly. Setting headers incorrectly can not only cause a false sense of security, they may even be detrimental to its security posture. Veracode feels security headers are an important layer of defense and wishes to enable developers to easily and correctly configure their site. If unsure about a particular header or setting, there is a wonderful resource that tracks browser support.
X-XSS-Protection
Purpose
This response header can be used to configure a user-agent's built in reflective XSS protection. Currently, only Microsoft's Internet Explorer, Google Chrome and Safari (WebKit) support this header.
Valid Settings
- 0 - Disables the XSS Protections offered by the user-agent.
- 1 - Enables the XSS Protections
- 1; mode=block - Enables XSS protections and instructs the user-agent 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 user-agent to report potential XSS attacks to a single URL. Data will be POST'd to the report URL in JSON format.
Common Invalid Settings
- 0; mode=block; - A common misconfiguration where the 0 value will disable protections even though the mode=block is defined. It should be noted that Chrome has been enhanced to fail closed and treat this as an invalid setting but still keep default XSS protections in place.
- 1 mode=block; - All directives must be separated by a ;. Spaces and , are invalid separators. However, IE and Chrome will default to sanitizing the XSS in this case but not enable blocking mode as everything after the 1 is considered invalid.
How To Test
Internet Explorer will display a dialog box if reflective XSS was detected and sanitized or blocked. Chrome will hide the output of the reflective XSS attack in the response when it is set to 1. When it is set to 1; mode=block, Chrome will redirect the user-agent to an empty data:, URL.
External References
- Post from Microsoft on the X-XSS-Protection Header
- Chromium X-XSS-Protection Header Parsing Source
- Discussion of report format in WebKit bugzilla
X-Content-Type-Options
Purpose
This header can be set to protect against MIME type confusion attacks in Internet Explorer 9, Chrome and Safari. Firefox is currently debating the implementation. Content sniffing is a method browsers use to attempt to determine the 'real' content type of a response by looking at the content itself, instead of the response header's content-type value. By returning X-Content-Type-Options: nosniff, certain elements will only load external resources if their content-type matches what is expected. As an example, if a stylesheet is being loaded, the MIME type of the resource must match "text/css". For script resources in Internet Explorer, the following content types are valid:
- application/ecmascript
- application/javascript
- application/x-javascript
- text/ecmascript
- text/javascript
- text/jscript
- text/x-javascript
- text/vbs
- text/vbscript
For Chrome, the following are supported MIME types:
- text/javascript
- text/ecmascript
- application/javascript
- application/ecmascript
- application/x-javascript
- text/javascript1.1
- text/javascript1.2
- text/javascript1.3
- text/jscript
- text/livescript
Valid Settings
- nosniff - This is the only valid setting, it must match nosniff.
Common Invalid Settings
- 'nosniff' - Quotes are not allowed.
- : nosniff - Incorrectly adding an additional : is also invalid.
How To Test
Open the developer panel in Internet Explorer or Chrome and observe the difference between: having nosniff and not having nosniff set in the console output.
External References
- Microsoft Post on Reducing MIME type security risks
- Chromium Source for parsing nosniff from response
- Chromium Source list of JS MIME types
- MIME Sniffing Living Standard
X-Frame-Options
Purpose
This header is for configuring which sites are allowed to frame the loaded resource. Its primary purpose is to protect against UI redressing style attacks. Internet Explorer has supported the ALLOW-FROM directive since IE8 and Firefox from 18. Both Chrome and Safari do not support ALLOW-FROM, however WebKit is currently discussing it.
Valid Settings
- DENY - Denies any resource (local or remote) from attempting to frame the resource that also supplied the X-Frame-Options header.
- SAMEORIGIN - Allows only resources which are apart of the Same Origin Policy to frame the protected resource.
- ALLOW-FROM http://www.example.com - Allows a single serialized-origin (must have scheme) to frame the protected resource. This is only valid in Internet Explorer and Firefox. The default of other browsers is to allow any origin (as if X-Frame-Options was not set).
Common Invalid Settings
- ALLOW FROM http://example.com - The ALLOW-FROM directive must use the hyphen character, not a space between allow and from.
- ALLOW-FROM example.com - The ALLOW-FROM directive must use an URI with a valid scheme (http or https).
How To Test
Visit the test cases and view the various options and how the browser responds to framing the resources.
External References
Strict-Transport-Security
Purpose
The Strict Transport Security (STS) header is for configuring user-agents to only communicate to the server over a secure transport. It is primarily used to protect against man-in-the-middle attacks by forcing all further communications to occur over TLS. Internet Explorer does not currently support the STS header. It should be noted that setting this header on a HTTP response has no effect since values could easily be forged by an active attack. To combat this bootstrapping problem, many browsers contain a preloaded list of sites that are configured for STS.
Valid Settings
The following values must exist over the secure connection (HTTPS) and are ineffective if accessed over HTTP.
- max-age=31536000 - Tells the user-agent to cache the domain in the STS list for one year.
- max-age=31536000; includeSubDomains - Tells the user-agent to cache the domain in the STS list for one year and include any sub-domains.
- max-age=0 - Tells the user-agent to remove, or not cache the host in the STS cache.
Common Invalid Settings
- Setting the includeSubDomains directive on https://www.example.com where users can still access the site at http://example.com. If example.com does not redirect to https://example.com and set the STS header, only direct requests to http://www.example.com will be automatically redirected to https://www.example.com by the user-agent.
- max-age=60 - This only sets the domain in the STS cache for 60 seconds. This is not long enough to protect a user who accesses the site, goes to their local coffee shop and attempts to access the site over http first.
- max-age=31536000 includeSubDomains - Directives must be separated by a ;. In this case Chrome will not add the site to the STS cache even though the max-age value is correct.
- max-age=31536000, includeSubDomains - Same as above.
- max-age=0 - While this is technically a valid configuration. Many sites may do this accidentally, thinking a value of 0 means forever.
How To Test
Determining if a host is your STS cache is possible by accessing "chrome://net-internals/#hsts" in Google Chrome. First, check if the domain is in the STS cache by using the Query Domain option. Next, visit the site that returns the STS header over HTTPS and attempt to query it again to determine if it was added successfully.
External References
Public-Key-Pins (Draft Header)
Purpose
This header is still under draft specification but may have clear security impacts so it has been added to this list. The purpose of the Public-Key-Pins (PKP) header is to allow site operators to provide hashed public key information to be stored in the browser's cache. Much like it Strict-Transport-Security header it will help user's from active man-in-the-middle attacks.The header may include multiple pin-<hash algorithm> directives. For example, pin-sha256=base64(sha256(SPKI)). The base64 encoded sha256 hash is the result of hashing the Subject Public Key Info (SPKI) field of an X.509 certificate. While the specification or implementations may change, it was observed that not encapsulating the hashes in quotes is invalid and the hashes will not be added to the PKP cache in Chrome 33. This header acts much like STS by including the max-age and includeSubDomains directive. Additionally, PKP supports a Public-Key-Pins-Report-Only header which can be used to report violations but will not enforce the pinning of certificate information, however this does not appear to be implemented in Chrome yet.
Valid Settings
- max-age=3000; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; - Pins this host for 3000 seconds using the base64 encoded sha256 hash of the x.509 certificate's Subject Public Key Info with hashes properly encapsulated in quotes.
- max-age=3000; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; report-uri="http://example.com/pkp-report" - Same as above but allows violations to be reported. Note that if this value is sent in the Public-Key-Pins header the user-agent should enforce and report violations. If the value is sent in Public-Key-Pins-Report-Only it will not be enforced but violations will be reported to the defined site.
Common Invalid Settings
- max-age=3000; pin-sha256=d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=; - Not encapsulating the hash value in quotes leads to Chrome 33 not adding the keys to the PKP cache. This mistake was observed in all but one of the four sites that returned this or the report-only header response.
How To Test
Using the same method as Strict-Transport-Security additional information under the pubkey_hashes field should be visible, if the site successfully had the PKP hashes added.
External References
- Public-Key-Pins draft specification
- Chrome issue tracking the implementation of Public-Key-Pins
- Chromium source code for processing Public-Key-Pins header
Access-Control-Allow-Origin
Purpose
Access-Control-Allow-Origin is apart of the Cross Origin Resource Sharing (CORS) specification. This header is used to determine which sites are allowed to access the resource by defining either a single origin or all sites (denoted by a wildcard value). It should be noted that if the resource has the wildcard value set, then the Access-Control-Allow-Credentials option will not be valid and the user-agent's cookies will not be sent in the request.
Valid Settings
- * - Wildcard value allowing any remote resource to access the content of the resource which returned the Access-Control-Allow-Origin header.
- http://www.example.com - A single serialized origin (http://[host], or https://[host]).
Common Invalid Settings
- http://example.com, http://web2.example.com - Multiple serialized origins separated by a comma or space. Only a single origin is possible.
- *.example.com - Wildcard subdomain origins defined such as: *.domain.com. Only a single origin is possible.
- http://*.example.com - Same as above
How To Test
It is easy to determine if the header is configured properly because if it is not, the CORS request will simply fail to return any data.
External References
Content-Security-Policy 1.0
Purpose
Content Security Policy is a collection of directives which can be used to restrict how a page loads various resources. Currently, Internet Explorer only supports a subset of CSP and only with the X-Content-Security-Policy header. Chrome and Firefox currently support 1.0 of CSP, however version 1.1 of the policy is currently being developed. Configured properly it can help protect a site's resources from various attacks such as XSS and UI redressing related issues. There are 10 possible directives which can each be configured to restrict when and how resources are loaded.
- default-src - This directive sets defaults for script-src, object-src, style-src, img-src, media-src, frame-src, font-src and connect-src. If none of the previous directives exist in the policy the user-agent will enact the rules of the default-src values.
- script-src - Also has two additional settings:
- unsafe-inline - Allows the resource to execute script code. An example would be code that exists in an HTML element's on* event values, or the text content of a script element inside the protected resource.
- unsafe-eval - Allows the resource to execute code dynamically in functions, such as eval, setTimeout, setInterval, new Function etc.
- object-src - Determines where plugins can be loaded and executed from.
- style-src - Determines where CSS or style markup can be loaded from.
- img-src - Determines where images can be loaded from.
- media-src - Determines where video or audio data can be loaded from.
- frame-src - Determines where frames can be embedded from.
- font-src - Determines where fonts can be loaded from.
- connect-src - Restricts which resources can be used in XMLHttpRequest, WebSocket and EventSource.
- sandbox - An optional directive which specifies a sandbox policy for 'safely' embedding content into a sandbox.
There is also the report-uri directive which can be used to send reports when the policy is violated to a specified URL. This can be helpful for both debugging and being notified of an attack. Additionally, a second header of Content-Security-Policy-Report-Only can be defined to not enforce CSP but to send potential violations to a report URL. It follows the same syntax and rules as the Content-Security-Policy header.
Valid Settings
Common Invalid Settings
How To Test
Open the developer panel and view the console in Chrome or Firefox to view any potential violations while debugging a site.