Monthly Archives: December 2021

Is your CSP header implemented correctly?

A Study of CSP Headers employed in Alexa Top 100 Websites

Introduction

The Content Security Policy (CSP) is a security mechanism web applications can use to reduce the risk of attacks, such as XSS, code injection or clickjacking, by informing the browser that something should be blocked when loading or parsing the HTML content. The CSP header has become a standard metric to improve the security posture of modern applications as most application security tools would likely flag a security issue in your applications if it detects the absence of the CSP headers.

How Content-Security-Policy works
How Content-Security-Policy Works

Recently I was tasked to add a CSP header to one of our applications to ensure it is fully equipped to combat some potential XSS issues.  After spending a while investigating which CSP policies would be a good candidate to use, I found it is not an easy task to implement a thorough CSP header while avoiding breaking legitimate site functionality. Then I decided to check how other popular web applications are utilizing CSP headers and how I could learn from them to build a robust CSP header.

How Alexa Top 100 websites are adopting CSP header 

I started to evaluate How Alexa Top 100 websites are adopting CSP header to harden its security posture by checking whether these websites are adding CSP headers and analyzing whether these CSP headers are really useful to protect against some common attacks, such as  XSS and Clickjacking.  When analyzing the CSP headers in these top websites, I was using Google CSP Evaluator to check how each CSP directives are defined  in the CSP headers besides manual testing.  The result is kind of bittersweet as there are some unexpected behaviors and implementations of CSP headers on these top websites.  Below are some findings worthy to be mentioned

Findings 

Finding 1: 51 out of Alexa Top 100 websites have CSP header added

Though I was expecting that every website in Alexa Top 100 websites  should have CSP header implemented by considering these websites attract millions of users on a daily basis, it turns out only 51 websites out of Alexa Top 100 have CSP headers enabled in the web application. 

Right, more than 50% of the websites are at least using CSP headers (some of them are use Content-Security-Policy-Report-Only), that is not that bad comparing to the statistics, less than 4% of URLs are carrying CSP headers by referring to a Google Research works

But if you get a closer look at the CSP headers employed in these 51 websites, some of them are only used to protect against Clickjacking attacks, some of them are using the CSP header as Report-Only mode.  The worst part is that most of these CSP headers are not implemented correctly to mitigate potential attacks due to misconfiguration.

Finding 2:   More than half of the websites are suffering from common CSP misconfiguration

Misconfiguration 1:  ’unsafe-inline’ keyword without specifying a nonce defined in script-scr directives

According to Google research ‘unsafe-inline’ within script-src directive is the most common security misconfiguration for Content Security Policy (CSP) and 87.6% CSP employed the ’unsafe-inline’ keyword without specifying a nonce, which essentially disables the protective capabilities of CSP against XSS exploitation. 

There are 34  websites where ‘unsafe-line’ is specified under script-src directive in the CSP configuration. Whereas,  18 out of these 34 websites (roughly 50%) are using the ‘unsafe-inline’ keyworks without specifying a nonce or a hash, which means the CSP header is not configured in a correct way to mitigate XSS exploitation. 

This finding is really astonishing as it means around 50% of these 34 heavily visited websites (including facebook, ebay, shopify) are not configuring CSP header in a correct way. Following is a snapshot where ‘unsafe-inline’ is specified without a nonce in the a CSP header employed by one of the Alexa Top 100.

Content-security-policy: default-src ‘self’ blob: wss: data: https:; img-src ‘self’ data: https:; script-src ‘self’ ‘unsafe-eval’ ‘unsafe-inline’ blob: data: https:; style-src ‘self’ ‘unsafe-inline’ data: https:;  report-uri /csp/report

Misconfiguration 2:  data: URI  schema is allowed in some directives

While around 50% of CSP employed the ‘unsafe-line’ keyword without specifying a nonce, there is another misconfiguration scenario where data: URI scheme is allowed for script-src, frame-src, object-src directive, this misconfigure also defeats the XSS protection of CSP header.

Around 25% of CSP headers employed by the Alexa Top 100 websites are using data:uri under its script-src, frame-src or object-src directives (or default-scr directive when script-src directive is missing).  For example, the following XSS attack is utilizing data:uri schema to pass malicious javascript code under your application

<iframe/src=”data:text/html,<svg onload=alert(1)>”></iframe>
<script src=”data:text/javascript,alert(1)”></script>

Misconfiguration 3:  object-src directive allows * as source or is missing (no fallback due to absence of default-src)

In some CSP headers employed by the Alexa Top 100, * (wildcard) is used in object-src directive or default-src directives, which significantly reduce the protection of CSP header as there are multiple ways to inject malicious javascript code when * is used for these directives.

The following CSP header is extracted from one of  website  

Content-Security-Policy: default-src data: ‘self’ ‘unsafe-inline’ ‘unsafe-eval’ worker-src blob: ‘self’;  connect-src * wss: blob:;  font-src * data: blob:; frame-src * blob: ‘self’;  img-src * data: blob: about:;  media-src * data: blob:;  object-src *;  report-uri /csp/report;

If the website has a XSS vulnerability, an attacker could use the following payload to bypass its CSP header

<object data=”data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=”></object>

These misconfigurations do not mean the CSP header is not effective at all though these misconfiguration makes CSP protection weak, even useless in some cases.

Finding 3: Some minor issues are ignore in the CSP headers

Ignored issue 1:  unsafe-inline are widely added without nonce for style-src directive

Most security engineers downplay the potential security risks imposed by inline style, which is perfectly proved by the data we collected by reviewing CSP header in Alexa Top 100 websites. Among the CSP headers employed by these websites, much more CSP headers  are allowing inline style compared to allowing inline script

NO. of websites using unsafe-inline keyword without nonce under script-src directive16
NO. of websites using unsafe-inline keyword without nonce under style-src directive22

Though allowing inline style is not as bad as allowing inline script without a nonce, inline style could open the door for a number of attacks like injecting a css keylogger  to steal sensitive data. It means, it still makes some sense to add nonce under style-src directive to prevent potential attack by using inline style

Ignored Issue 2:  No Access Control or throttling method added to the report-uri endpoint to preventing malicious user from abusing it

The ‘report-uri’ is a very powerful feature built into CSP that allows website adminstrator to gain insight on their deployed policy by instructing the user agent to report attempts of violating the CSP to the report uri endpoint .  You can enable CSP’s reporting feature by specifying the URL of your reporting endpoint with a report-uri directive in your policy. Take the CSP header employed by instragram.com for example, all the violation of CSP policy will be reported to https://www.instagram.com/security/csp_report/

Content-security-policy: report-uri https://www.instagram.com/security/csp_report/; default-src ‘self’ https://www.instagram.com; img-src data: blob: https://*.fbcdn.net https://*.instagram.com https://*.cdninstagram.com https://*.facebook.com https://*.fbsbx.com https://*.giphy.com; font-src data: https://*.fbcdn.net https://*.instagram.com https://*.cdninstagram.com; media-src ‘self’ blob: https://www.instagram.com https://*.cdninstagram.com https://*.fbcdn.net; manifest-src ‘self’ https://www.instagram.com; script-src ‘self’ https://instagram.com https://www.instagram.com https://*.www.instagram.com https://*.cdninstagram.com wss://www.instagram.com https://*.facebook.com https://*.fbcdn.net https://*.facebook.net ‘unsafe-inline’ ‘unsafe-eval’ blob:; style-src ‘self’ https://*.www.instagram.com https://www.instagram.com ‘unsafe-inline’; connect-src ‘self’ https://instagram.com https://www.instagram.com https://*.www.instagram.com https://graph.instagram.com https://*.graph.instagram.com https://i.instagram.com/graphql_www https://graphql.instagram.com https://*.cdninstagram.com https://api.instagram.com https://i.instagram.com https://*.i.instagram.com wss://www.instagram.com wss://edge-chat.instagram.com https://*.facebook.com https://*.fbcdn.net https://*.facebook.net chrome-extension://boadgeojelhgndaghljhdicfkmllpafd blob:; worker-src ‘self’ blob: https://www.instagram.com; frame-src ‘self’ https://instagram.com https://www.instagram.com https://*.instagram.com https://staticxx.facebook.com https://www.facebook.com https://web.facebook.com https://connect.facebook.net https://m.facebook.com; object-src ‘none’; upgrade-insecure-requests

There are many benefits of enabling a report-uri directive for CSP as the CSP violation report might indicate some attempts to bypass or violate your CSP policy to exploit some vulnerability.  But this feature also introduces some concerns due to the way how the report-uri endpoint is implemented. 

One concern is that any users could send massive invalid CSP violation reports to the report-uri endpoint as most of these report-uri endpoints have no access control or throttle method to prevent this kind of attack. Due to the massive invalid CSP violation, it may make it really harder to spot legitimate attempts to violate CSP policy. In some scenarios, if the report-uri endpoint is not scalable and a high volume of invalid CSP violation report could cause DOS of the endpoint. 

CSP itself  is a very rich feature as it has a dozen of directives that a user could specify. I am pretty sure that you would spot some other funky or interesting  implementations of CSP implementations under the Alexa Top 100 websites. Besides that, to define a robust CSP policy without breaking the applications is not that easy. For example, some disallowing inline script CSP policy could break desired features of jQuery. That could explain why these top tier websites. 

Conclusion

While CSP could be very helpful as a part of a defense-in-depth strategy, your application should not completely rely on the protection of  CSP headers  as a sole defensive mechanism as misconfigurations could make the protection being bypassed easily. The CSP data collected from the Alexa Top 100 is just a tip of the iceberg. I believe there are much more misconfigurations in the wild.

Applying a DAST tool or SAST tool to find potential vulnerabilities, for example, XSS and Clickjacking, and eliminate  them is the most efficient solution as CSP header does not eliminate the security flaws but make the exploitation hard.