The October 2014 edition of this report adds back the much needed analysis of changes, additions and removals of security headers. These are important metrics as it allows us to gain insight into how web site operators are reacting to the changes of their web resources. Now that we have a previous report to compare against, we can once again generate these statistics and do a full analysis. As before, it is strongly recommended that our post on setting security headers is reviewed to understand what these headers do and guidelines on how to set them properly in your environment.
There were no major architectural changes this time, only additional reporting functions created to aid in automating the process. As always, the scanner’s User-Agent strings were updated to reflect the latest versions of Mozilla Firefox and Google Chrome.
The scan took place on October 8th 2014. Using the latest Alexa Top One Million Web Sites. For results, we had a total of 3,016,983 responses. Firefox having 1,508,198 and Chrome having 1,508,785. Firefox had 942,417 HTTP and 565,781 HTTPS responses. Chrome had 942,957 HTTP and 565,828 HTTPS responses. A total of 25,001,569 headers were collected and processed by our scanner in roughly two hours.
Comparing our previous scan which took place in March 2014, there were 728,728 Firefox and 729,108 Chrome URLs that overlapped with this scan. This is more than enough overlap to give a good statistical representation of the state of change of the headers over the course of seven months.
Comparing changes between the runs turns out to be a non-straightforward endeavor and it is worth highlighting how it was conducted and what to expect. When comparing changes it is important to understand how the results were calculated. For added headers, we calculated where the header existed in one run, by browser, where it did not exist in the previous run, provided the URLs existed in both runs. For removed headers, the process was the same, only reversed. The only catch is to ensure that conflicting headers were not added to the count. Conflicting headers are when the server sends two header names back with different, conflicting values. These were removed from all comparisons.
Additionally, we included ‘invalid’ values in all comparison counts, so consider a small margin of error. We left the invalid values in as they still give a glimpse into what sorts of changes web site operators are attempting to implement, not whether or not they were correct in it. When calculating the changes, queries were done to ensure case insensitivity and whitespace trimmed. All descriptions and indepth reviews of changes were analyzed using Firefox, except in the case of X-WebKit-CSP in which Chrome was used for describing what changed.
Our results will be presented in order of security header with the current configurations and then a comparison against the last run in March 2014.
This header continues to have strong presence on sites with 1; mode=block being the most popular setting. Followed closely by blocking plus reporting. Unfortunately we are still seeing the incorrect setting of 0; mode=block. It looks like Chrome is still in the process of figuring out how to handle this.
While the majority of sites kept the same values, we did see a rather large change in removals. The majority of changes were due to sites adding the report-uri field. Almost all of them (1,486) changed to adding a GUID such as: “"1; mode=block; report=/xss-report/4994eedd-e817-4f04-9bb7-a4c9229476b0?source%5Baction%5D=index&source%5Bcontroller%5D=shop&source%5Bsection%5D=storefront"”. It turns out these URLs were subdomains of www.myshopify.com. Most likely, this was a change done on myshopify’s side which effected the large number of sites. Two sites went from filtering mode to blocking mode, and one site went from blocking mode to filtering mode.
The X-Content-Type-Options header continues to be a popular header. This is probably due to two reasons; one it’s extremely simple to set, only a single value of nosniff is valid. Secondly, it has very little impact when set for a web resource.
Over 2500 sites added the X-Content-Type-Options header. However, there were still a large number of sites removing the header, over 600. The number of sites which changed the value was zero, again an indication that single purpose security headers with single values have extremely large benefits with adoption and maintenance.
One of the most popular security headers (alongside x-xss-protection and x-content-type-options) continues to see wide adoption. However, it is still has one of the highest invalid setting counts (bested only by access-control-allow-origin).
The X-Frame-Options header saw the most amount of added and removed. Over 6,000 sites added the header from the last scan. Changes to the values were relatively low, only 280 or so opting to attempt different values. Of those, the majority moved towards using SAMEORIGIN, with 100 sites using the setting. 60 moved to using DENY and only 21 moving to allow-from with a single origin specified.
This is the only header that had a significant change to its possible values. While not part of RFC6797, browsers have elected to include a ‘preload’ directive. This allows a site, under certain restrictions, to elect to include themselves in a browser’s preload list. The restrictions for the values are that the max-age value must be greater than 10886400 seconds, must include the includeSubdomains directive and include the preload directive. For a full list of requirements, see the preload site.
There were 23 sites which did not include the includeSubdomains directive along with setting max age above the valid threshold and included the preload directive. (Note: these were not counted in the invalid result, but were counted in the preload field, even though they are technically invalid for preload). A single site did not have the maximum max-age value set to be allowed for the preload list. This site also failed to include the includeSubdomains directive.
Changes for Strict-Transport-Security, as with all STS stats, only include HTTPS URLs. Given the low number of sites using it, it is surprising to see how many were added in the last seven months, over 1000. Changes were a bit more interesting. Four sites moved from invalid settings to valid settings. 115 sites went from a lower max-age to a higher one. 18 sites went from a larger value to a smaller value for max-age, where 30 sites stayed the same. 32 sites included the includeSubdomain directive and 10 removed it.
The Access-Control-Allow-Origin continues to be plagued with sites specifying the values incorrectly. The wildcard setting also continues to dominate most sites which use the header.
Given its overall prevalence, it’s interesting to see it was added to so many sites. While only 10,000 or so sites use the header, it jumped 2000 additions since the last run. This is as many as X-Content-Type-Options and X-XSS-Protection even though those headers are used in far more many sites. 309 of the sites elected to switch from a wildcard to a single origin whereas only 25 sites went from a single origin to wildcard. The majority of sites moving from wildcard to single origin URLs came from http://my.tv.sohu.com and its various user pages.
Compared to last run, which only had about 350 sites using CSP, we now are seeing over 800 for Chrome, basically doubling. However, it’s still one of the least used security headers. Also, the CSP specification has changed quite a bit. New directives and attributes, such as supporting x-frame-options like features have been added. The inline or unsafe directives still are widely used, on 700 of the 800 sites. There are still a large number of sites, around 200 or 1/4th of the CSP enabled sites, that are still sending both X-Content-Security-Policy (Firefox) or X-WebKit-CSP (Chrome) along with Content-Security-Policy.
- reflected-xss allow is equivalent to X-XSS-Protection: 0
- reflected-xss filter is equivalent to X-XSS-Protection: 1
- reflected-xss block is equivalent to X-XSS-Protection: 1; mode=block
Additionally, a nonce attribute has been added to allow for resources to trust certain scripts for execution. It is a workaround to help web site operators whitelist certain script blocks who cannot avoid including inline script.
None of these were found in the current or previous scans.
Interestingly, the biggest change to Content-Security-Policy was sites being added, over 280 for Firefox. Around 50 sites elected to remove Content-Security-Policy. A closer look at these sites revealed that almost all of them were using the most permissive versions of CSP with most directives set to * and unsafe-eval and unsafe-inline set. The changes between runs were of not much interest, with most changes relating to modifying the allowed domains or hosts for various directives.
X-Content-Security-Policy & X-WebKit-CSP
Sadly, still quite a few sites are using the deprecated X-Content-Security-Policy and X-WebKit-CSP headers. Much like Content-Security-Policy the majority are using inline or unsafe script methods.
X-Content-Security-Policy & X-WebKit-CSP Changes
Even worse, we observed over 100 sites adding the headers since our last run. About 25 of these can be attributed to phpMyAdmin which we discussed in our last post.
Last time, only three sites responded with this draft header, this time has seen little addition, a total of five sites are now using the header.
It is nice to have the ability to compare runs as it gives us a much better view into how adoption is taking place among the various headers. As expected those with the most number of users see the most fluctuation of additions and removals. One thing that seems clear; simple, single purpose security headers continue have wider adoption because their effects are well known and they are extremely easy to configure. The ambiguity of headers such as Access-Control-Allow-Origin or CSP just raise the barrier of entry. Those two points pretty clearly demonstrate why CSP continues to have such a low adoption rate, even though it’s been two years since it was adopted as a W3C candidate.
As always, I give my thanks; to Ian Melven of New Relic for pushing me to do this analysis, Mike West of Google for pointing me to information on STS’s preload feature and our own Jason Montgomery for helping me with some of the more complex SQL queries!