- Subresource Integrity TagHelper Using ASP.NET Core - Part 1
- Subresource Integrity TagHelper Using ASP.NET Core - Part 2
Last week I wrote part one of a blog post discussing a Subresource Integrity (SRI) tag helper I wrote for ASP.NET Core. It turns out the post was featured on the ASP.NET Community Standup and discussed at length by Scott Hanselman, Damian Edwards and Jon Galloway. Here is the discussion:
The overall impression from the standup was that the SRI tag helper I wrote was a good first step but there was more work to be done. It was however, still more secure than "the rest of the internet" according to Jon Galloway. The main issue raised during the standup was that the first call made to get the resource could retrieve a version of it that was compromised.
My initial thinking was that you could check the files at deployment time when the tag helper first runs. Then the tag helper would have calculated the hash and cached it without any expiration time, so you are good from then on. In hindsight checking the files on every deployment is not great for the developer.
The 2nd Iteration
So for the next iteration I have added a new alternative source attribute, basically a local file from which the SRI is calculated. Now the tag helper looks like this when in use:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js" asp-subresource-integrity-src="~/js/jquery.min.js"></script>
You can also customize the hashing algorithm used in your SRI. You can choose between SHA256, SHA384 and SHA512, by default the tag helper uses the most secure option SHA512 which seems to be supported by all browsers. Should you choose to use a different hashing algorithm or even use more than one algorithm, you can set the
asp-subresource-integrity-hash-algorithms attribute which is just a flagged enumeration (Note that I am using ASP.NET Core RC2 syntax, where the name of the enumeration can be omitted):
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js" asp-subresource-integrity-src="~/js/jquery.min.js" asp-subresource-integrity-hash-algorithms="SHA256 | SHA384 | SHA512"></script>
What is it doing behind the scenes?
- Reads the local file specified using the asp-subresource-integrity-src attribute.
- Calculates a SHA512 hash (or your custom selection) for the file.
- Adds the
crossoriginattributes to the script tag.
- Adds the hash value to the distributed cache (
IDistributedCache) built in to ASP.NET Core with no expiry date. If you are using a distributed cache like Redis (Which you should for the pure speed of it) then the hash will be remembered.
- The next time the page loads, the hash is retrieved from the cache, so there is very little performance impact of this tag helper.
Microsoft CDN Still Broken for SRI
In my last post I noted that SRI requires that the resource has a valid
Access-Control-Allow-Origin HTTP header (usually with a
* value). Microsoft's CDN does not supply this header for all it's resources. I did reach out to Microsoft to see if this could be fixed. I've not heard back yet. I would imagine that with a CDN of that size, fixing this issue is a non-trivial thing so it might take time but I'll do some more chasing.
Browser Extensions and SRI
Last week, I noted that leaving out the scheme in the URL for your CDN resource e.g.
//example.com/jquery.js caused Firefox to error and fail to load the resource completely and I recommended that you always include the
https:// scheme. It turns out that this was not Firefox causing the issue at all but a Firefox browser extension. I've yet to figure out which one yet as I have quite a few installed (most of them security related because I'm paranoid) but it's probably an extension called HTTPS Everywhere which attempts to use HTTPS if it is available. To be on the safe side and avoid this problem, always specify the
So what happens when a CDN script is maliciously edited or (much more likely) you messed up and your local copy of the CDN script is different from the one in the CDN? Well, this is where CDN script fallbacks come in. There is already a tag helper provided by ASP.NET Core that does this:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js" asp-subresource-integrity-src="~/js/jquery.min.js" asp-fallback-src="~/js/jquery.min.js" asp-fallback-test="window.jQuery"> </script>
A big shout out to Gabor Szathmari and his website sritest.io. It is able to scan your page and check that all your external resources have SRI enabled and most importantly that it has been setup correctly. You could use the console window from a browser like Chrome or Firefox but this website will also tell you if you've forgotten to add SRI to any external resources and also highlight edge cases such as the ones I highlighted in these two blog posts.
Where Can I Get It?
This tag helper is available in a few ways: