Tag Archives: Implementation

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.

Using JWT? You need avoid these implementation mistakes

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. JWT are widely used in authentication, authorization and information exchange. Among these use cases, the most common scenario for using JWT is for authorization purpose. Once a user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. You may start to ask why not using Session token. One reason is that the JWT is stateless compared with Session tokens, it means that the server side does not have to store the JWT in a centralized DB to perform the validation when a clients sends a request to the server, whereas, the server has to store the session cookies for validation purpose.

To understand the common implementation mistakes of JWT, we need first figure out the structure of the JWT token as most the implementation errors are caused by misunderstanding the structure of JWT token and how each component of JWT are used for.

Structure of JWT Token

A well-formed JWT consists of three concatenated Base64url-encoded strings, separated by dots (.):

  • Header : contains metadata about the type of token and the cryptographic algorithms used to secure its contents. For example
{
  "alg": "HS256",
  "typ": "JWT", 
  "kid": "path/value" //optional
}
  • Payload : contains verifiable security statements, such as the identity of the user and the permissions they are allowed. An example of the payload could be
{
  "username": "test@example.com",
  "id": "new user"
}
  • Signature : it is used to validate that the token is trustworthy and has not been tampered with. When you use a JWT. Signature is piece of encrypted data of the Header and Payload date by using certain encryption method (such as HMAC,SHA256) with a secret which should be residing on a server side.
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

After putting all them together, a JWT looks like

Common Implementation Error

JWT itself is considered as secure method. Most of the security issues discovered against JWT are caused by implementation mistakes.

Leak the secret key

JWT is created with a secret key and that secret key is private to you which means you will never reveal that to the public or inject inside the JWT token. However, sometimes, the developers could mistakenly leak the signing secret to public. For example, the JWT signing secret is stored on a client side javascript functions or stored on a public accessible files. As a consequence, an attacker could bypass the signature verification easily as the attacker could sign any payloads with the secret to put the server side signature validation in vain. Here is one example listed under Hackerone where the developers are adding hardcoded secret in the client side javascript file.

Using Predictable secret key

It is also possible that the developers are copying a piece of code from a sample code base when implementing the JWT on the server side or they are using a simple word (not randomly generated complex string) as the secret value when implementing the JWT on the server side . A brute force attack could easily extract the secret key as the attacker knows the algorithm, the payload with the original information and the resulting signature of the encrypted payload and header. One example listed under Hackerone shows how a developer is using the ‘secret’ as the secret when implementing the JWT on the server side.

Broken JWT Validation

There are numerous way how the JWT validation could be broken during insecure implementation. Here are some typical examples where a broken JWT validation could happen.

  • Not Validate Signature at all. Some developers implement the JWT validation in a wrong way, where they only decode the JWT payload part without validating the signature part before accepting the JWT as a valid token.
  • Not Validate the JWT correctly if None alg is provided. An attacker could or creates a token by setting alg (the signing algorithm) to None in the header. If the server side is NOT validating whether the None alg was really implemented when the JWT was generated. As a consequence, any JWT provided by the attacker with a None value to the alg will be treated as a valid token. To prevent this, the server side should check whether the alg value is the one when the JWT token is generated. If not, the JWT should be treated as an invalid.
  • Not Validate the JWT correctly when alg is changed to HS256 from RS256. HS256 is a symmetric encryption method, the server side is using the same key to generate and validate the JWT. Whereas, RS256 is an asymmetric encryption method, the JWT payload was signed with its private key and validated with the public key, which is known to the public. Now An attacker creates the token by setting the signing algorithm to a symmetric HS256 instead of an asymmetric RS256, leading the API to blindly verify the token using the HS256 algorithm using the public key as a secret key. Since the RSA public key is known, the attacker can correctly forge valid JWTs and bypass the validation method.

Lack of kid header parameter validation

The kid (key ID) Header Parameter is a hint indicating which key was used to secure the JWS. This parameter allows originators to explicitly signal a change of key to recipients. With the key identifier, the consumer of a JWT can retrieve the proper cryptographic key to verify the signature. This simple mechanism works well when both the issuer and consumer have access to the same cryptographic key store.

Since the attacker can modify the kid header parameter, attacker can supply any values in there when it is sent to the sever. If the server is not validating or sanitizing the kid value correctly, it could lead to severe damage.

For example, the kid value in the JWT header is specifying the location of the JWT secret to sign the JWT payload

{
  "alg": "HS256",
  "typ": "JWT", 
  "kid": "http://localhost:3000/vault/privKey.key"
}

For example, the kid value in the JWT header is specifying the location of the JWT secret to sign the JWT payload

{
  "alg": "HS256",
  "typ": "JWT", 
  "kid": "http://evil.com/privKey.key" //Private key supplied by the attacker
}

Now, if the attacker is providing his own private key to the kid parameter and adjust the JWT token, he would be able to generate any valid JWT token.

Other wrong implementation

The above implementation mistakes could lead to very severe security issues, for example, account hijacking and authentication bypass. There are some other implementation bad practice should be avoid when using JWT token.

  • Use JWT token as session cookie. Some applications are using JWT token as a session cookie and it could cause havoc. Let’s say you have a token and you revoke it due to a user logout or any other action, you could not really invalidate the token before its expiration has been reached unless you keep a DB to store these tokens and build a revocation list, which is not the intention of using a stateless JWT.
  • Leak the JWT in referrer header. It is common that a developer attaches the JWT in a URL, for example, user registering and password reset service, and the HTML page of the URL are loading some 3rd party web pages. As a consequence, the JWT could be leaked to 3rd party web pages via referer header if noreferrer is not probably deployed in the web application.

Conclusion

JWT are adopted by more and more applications over the web. If used correctly,  it could help you to build a robust and agile authentication, authorization and information key functions.However, if misused or implemented incorrectly, this technology may put entire systems at risk. This JWT Security Cheat Sheet provides an overview of all these best practices when using JWT in your applications.