Security Headers on the Top 1,000,000 Websites: March 2013 Report

Back in November 2012 I did Veracode’s initial release of a security headers report on the top 1 million websites from the Alexa list. My goal was to turn it into a series so it would be possible to track how these sites change over time in regards to security headers that are added, removed or changed. For this recent scan, only a single change was made to the original scripts. The tool now sends a recent Chrome User-Agent to track if sites respond with different headers depending on the supplied User-Agent.

Only the Firefox User-Agent data was used when comparing the results with the previous November 2012 data set. Out of the original 1.25 million requests gathered from the November scan, a total of 719,355 URLs matched this most recent run. As for the new data, we had roughly the same amount of valid responses. There were a total of 1,256,787 responses for Firefox and 1,257,273 responses for Chrome. Both HTTP and HTTPS requests were sent to each site.

Changes, Additions and Removals

Each security header of the November 2012 and the March 2013 data sets were analyzed to see if sites had modified their value, added new headers or removed headers. A total of 2,450 new headers were added to the 719,355 URLs that exist between the two scans.

Similar to last time we tracked the following security relevant headers:

  • X-Frame-Options
  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Origin
  • Strict-Transport-Security
  • X-Content-Security-Policy
  • X-Webkit-CSP

Of these headers a total of 2,198 had been added, 75 had changed and 452 headers had been removed. The majority of those removed were X-Frame-Options (246) and Access-Control-Allow-Origin (166). To reiterate, only Firefox based User-Agent requests were used when comparing the two data sets.

security-headers-additions-changes-removals

The rate of change matches what we expect; more popular headers, such as X-Frame-options and Access-Control-Allow-Origin, saw the highest rate of change.

Calculating sites that added headers is straightforward; we simply identified sites with security headers that did not have any during the November scan. Sites that changed their header values are a bit more difficult to characterize because a number of sites include the same header multiple times in the response. It is quite common when parsing response headers that multiple headers have their values ‘merged’ into a single value, separated by a comma and a space. This is a documented behavior which can be found in section 4.2 in RFC 2616. As an example shown below, we see a site returning the X-Frame-Options header twice.

double-header-return

For our purposes, we merge these headers into a single value of “X-Frame-Options: SAMEORIGIN, SAMEORIGIN.” In some cases the number of times a header is returned changes depending on when we make the request, which can skew the results when comparing the two data sets. This is most likely due to load balanced servers in which one or more servers are configured differently.

One of the more interesting data points comes from sites that removed security headers. Of the 426 sites that removed the X-Frame-Options header, 226 had originally set the value to SAMEORIGIN. A similar pattern can be seen with Access-Control-Allow-Origin. Of the 166 sites that removed the header, 130 had originally set the value to *. Of the 18 sites that removed the Strict-Transport-Security header, most had previously set a very high timeout value.

March 2013 Results

The scan conducted on March 10, 2013 used the latest Alexa list available at that time. As with the previous scan, both HTTP and HTTPS connections were attempted. This time, a second set of HTTP and HTTPS requests were sent using the latest Google Chrome browser User-Agent. Unfortunately during the scan, not every site that responded in Chrome also responded in Firefox. While the next two charts show the varying result count between the two browsers, all detailed security header value results analyzed below will only be the distinct results of requests sent using both user-agents.

firefox-security-header-count

For this scan, we analyzed a total of 1,256,787 responses for Firefox. We see relatively the same distribution of headers configured. X-Frame-Options are still the most popular, followed by Access-Control-Allow-Origin.

chrome-security-header-count

For Chrome, we see roughly the same as we do for Firefox. However, when using the Chrome User-Agent we see a total of 96 sites using the X-Webkit-CSP header, by far the largest variance between the two browsers. While 96 may seem like a lot, 83 of these sites are owned by Facebook, so only 14 of these results can really be considered unique.

X-Frame-Options

This time the data was broken out a bit further than when we reported back in November. Invalid values were broken down further into sites that included conflicting headers. Conflicting headers means that a site returns two different header values for X-Frame-Options, such as a site returning DENY and SAMEORIGIN in the same response. Invalid values are simply that, for instance sites that configure Allow From (without a hyphen), or values such as ‘sameorigem’ (sic).

Overall SAMEORIGIN is still by far the most common setting, followed by DENY. GOFORIT is still used quite a bit with 215 sites configured with this value. Only twelve sites bothered to configure X-Frame-Options with an Allow-From origin list.

x-frame-options

Cross Origin Request Sharing (CORS) Headers

CORS continues to be a popular mechanism for sharing data between sites. As described in the previous post the Access-Control-Allow-Origin header determines which sites can request a User-Agent to send a request and read the response data. When configured with the wildcard value, any site can send requests and read the response data. However, if the request object attempts to send credentials to a site configured with a wildcard, the request will fail and no response data will be returned.

access-control-allow-origin

We still see the wildcard value being by far the most popular way of configuring Access-Control-Allow-Origin. Configured to allow a single origin is in a very far second, with people continuing to configure it with invalid values. Most of the invalid values continue to be hosts with wildcards, such as http://*.domain.com or simply *.domain.com with out the scheme, or multiple hosts specified in various ways. For a list of valid values, please consult our previous post on this subject.

For Access-Control-Allow-Credentials, only 217 sites set the property to true, five set it to false and three had it set to an invalid value.

Strict-Transport-Security

As last time we break STS values in to four broad categories; long max age, which is greater than 8000 seconds, short max age which is less than 8000 seconds, 0 which basically tells the User-Agent that the host should be removed from the browser’s HSTS list, and finally invalid values.

strict-transport-security

While the number of invalid values was quite low, we still see a max-age of 0 being quite high. Upon looking at the sites that have max age set to zero, the majority continue to be coming from www.etsy.com. As described last time, the reason for this can be attributed to their SSL opt-in policy.

Content-Security-Policy

There has only been a small change in sites using Content Security Policy. The biggest gain was in results for X-Webkit-CSP where we now seemingly have more X-Webkit-CSP responses than X-Content-Security-Policy. This can be attributed completely to Facebook. When using the Chrome User-Agent, popular user pages from Facebook began to respond with the X-Webkit-CSP header. In fact, 83 out of the 96 sites that had X-Webkit-CSP came from domains owned by Facebook. Unfortunately, we are still seeing a high amount of sites specifying the options “inline script” or “eval script”. For X-Webkit-CSP we have started to see the unsafe-eval which was also included in this count.

content-security-policy

Conclusion

Overall it is good to see the number of sites adopting security headers trending upwards. It was a bit surprising to see that Content Security Policy still doesn’t have too much adoption, but compared to other security headers it is far more complex to implement and has a higher chance of impacting how a site operates. In this sense, one can understand why it is taking longer than the other security headers to become mainstream. Invalid values specified in headers continue to be a problem. If you utilize any of these headers on your site it would be worth double checking the values configured against its relevant specification.

We feel this information could be useful in the community, so Veracode has decided to distribute the raw data used in this study. Both the November 2012 and March 2013 data sets are now available for download. To give a more accurate picture of our comparison, these archives contain the full list of web sites that were analyzed whether or not they had security headers in their responses.

Mike West | March 26, 2013 3:11 pm

Interesting data, thanks for doing this legwork!

For future surveys, I’d suggest including the unprefixed ‘Content-Security-Policy’ header, which is already supported in Chrome 25+, and is rapidly coming up in Firefox and Safari. I don’t expect many folks are using it yet, but it’d be good to set a baseline to see how things progress.

    Isaac Dawson | March 26, 2013 11:29 pm

    Excellent suggestion Mike! I just double checked, I extracted all headers ‘like’ content-security-policy so that data should actually be in the csv we put up for download. To satisfy your curiosity only 6 sites use content-security-policy. I will add that to my analysis next time I re-run the scan.
    Thanks again,
    -Isaac

Mike West | March 27, 2013 1:35 pm

Great, thanks! While I’m bothering you with feature requests for next time, ‘X-XSS-Protection’ usage would also be interesting. :)

James Vaughan | April 2, 2013 4:56 am

Some interesting stats Isaac, as you know at Recx we’ve been pushing the use of web security headers for some time via our Chrome plugin http://www.recx.co.uk/products/chromeplugin.php so good to see there is starting to be some adoption.

Although quite easy to enable the full complement of additional security controls, it’s not always without developer headaches. Debugging the fallout from enabling the options can be quite frustrating especially as the documentation, although complete, doesn’t allow easy adoption of what should be rapidly consumed additional security measures.

Ian Melven | May 24, 2013 9:14 pm

Once again I’m citing this blog post in a bug – thank you Isaac !

Derek Callaway | November 27, 2013 6:32 pm

Good observations, Isaac. Thanks for making the stats available. If you ever require access to a more generalized HTTP response header data set (or other strings for web test cases), query the IIS services used by Opera’s developers via some d0rkz. Here’s enough to get started:

http://devfiles.myopera.com/articles/554/httpheaders-url.htm
nice wget .. && sed .. | sort -u >a.lst

Please Post Your Comments & Reviews

Your email address will not be published. Required fields are marked *

RSS feed for comments on this post