Why does subresource integrity need the crossorigin attribute?

Subresource Integrity is a new security feature that safeguards websites against tampering of a script/stylesheet at the source. Say, you want to include a script from a public CDN, but you also protect yourself against potential manipulation of the code after you have included it, SRI is the way to go. The feature gives the developer the ability to add a hash-sum with the script tag. Before the browser loads the resource, it will match the hash-sum of the content with what is specified in the tag. If they are equivalent browser proceeds with execution, otherwise it’s blocked.

SRI Tag Example:

<script src="https://example.com/example-framework.js"
        integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8Kuxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
        crossorigin="anonymous"></script>

Besides the hash (specified with “integrity”), you also need the “crossorigin” attribute. The browser would refuse to load the script if it’s absent.

"Chrome SRI Error"

Why is the “crossorigin” attribute mandatory?

Short answer: security against cross origin policy violations

First, let’s understand what the attribute achieves. Crossorigin specifies how the browser should handle credentials (Cookies, HTTP Auth Info). It can have two values:

  • anonymous: The browser wouldn’t send credentials.
  • use-credentials: The browser will send them, but only if CORS headers specify the source site.

Example: Let’s say a script (https://example.com/abc.js) is being loaded on example-test.com via an SRI tag.

<script src="https://example.com/abc.js"
        integrity="sha384-..."
        crossorigin="anonymous"></script>

If crossorigin is set to “anonymous,” the browser will not send the cookies of example.com in the request header.

If it’s set to “use-credentials,” they will be sent, but only if the response headers of example.com, includes the access control header to whitelist example-test.com. Like: Access-Control-Allow-Origin: http://example-test.com. (More on CORS)

Note: Wildcard (*) in access control header is not allowed in this case.


The SRI spec explains the rationale behind the “crossorigin” attribute:

If that requirement were omitted, attackers could violate the same-origin policy and determine whether a cross-origin resource has certain content.

Attackers would attempt to load the resource with a known digest, and watch for load failures. If the load fails, the attacker could surmise that the response didn’t match the hash and thereby gain some insight into its contents. This might reveal, for instance, whether or not a user is logged into a particular service.

W3 SRI Specification

Example: Let’s say, https://facebook.com/xhr/login returns {status: true} if the user is logged in.

With the attribute absent, the SRI hash could be exploited to reveal that information. E.g., if the user visits example-test.com having a script tag on that page with the integrity hash-sum of {status: true}:

<script src="https://facebook.com/xhr/login"
        integrity="sha384-NmNN5X1LBy0ivZ+fJSALbHxo6hUaAT26+AsI2meLgS3x0IelsjT6asCIBN4oS7sV">
</script>

The default mode of the browser is to send credentials with the resource, which makes the attack trivial. If the script loaded successfully, then that means the user is logged in—information revealed by just a page visit.

The “crossorigin” attribute circumvents this problem by asking the developers to explicitly specify the credentials-sending behavior. It has been made necessary because browser’s default mode would have had disastrous implications.

Subscribe

Enjoyed this post? Get an email notification when I publish.

comments powered by Disqus