Skip to content

Subresource integrity

Marthijn van den Heuvel edited this page Sep 8, 2024 · 5 revisions

Subresource Integrity (SRI) is a security feature that enables browsers to verify that resources they fetch (for example, from a CDN) are delivered without unexpected manipulation. It works by allowing you to provide a cryptographic hash that a fetched resource must match.

Usage

First register the tag helpers in the _ViewImports.cshtml:

@* add specific tag helper *@
@addTagHelper Sidio.Web.Security.AspNetCore.Html.SubresourceIntegrityTagHelper, Sidio.Web.Security.AspNetCore

@* add all tag helpers *@
@addTagHelper *, Sidio.Web.Security.AspNetCore

And register the required services. By default, the hash algorithm is set to sha256 and the hash will be cached for 90 days.

builder.Services
    .AddSubresourceIntegrity();

Manually add integrity attributes

Then add the integrity taghelper attribute asp-add-subresource-integrity="true" to the script or link tag:

<link rel="stylesheet" href="https://example-cdn.com/bootstrap.min.css" asp-add-integrity="true" />
<script src="https://example-cdn.com/site.js" asp-add-integrity="true"></script>

Automatically add integrity attributes

Alternatively, the integrity attribute can be applied automatically to all script and link tags by configuring the tag helpers:

builder.Services
    .ConfigureTagHelpers(x => 
        {
            x.AutoApplySubresourceIntegrity = true;
        }
    );

Service configuration

builder.Services
    .AddSubresourceIntegrity(x => 
        {
            x.Algorithm = SubresourceHashAlgorithm.SHA512;
            x.AbsoluteExpiration = TimeSpan.FromDays(180);
        }
    );

Security notice

⚠️ The integrity hash by this service is generated by the server by requesting the resource. Because the resource can be malicious at the time the resource is requested, this feature is not 100% secure. It is recommended to generate and apply the SRI hashes manually.

The testing library can be used to verify all script tags have the integrity attribute applied:

public async Task MyControllerAction_ReturnsView()
{
    // arrange
    var client = _factory.CreateClient();

    // act
    var response = await client.GetAsync("/Home/Index");

    // assert
    response.IsSuccessStatusCode.Should().BeTrue();

    var content = await response.Content.ReadAsStringAsync();
    var scripts = HtmlParser.ExtractScriptTags(content);
    scripts.ShouldNotBeEmpty();
    scripts.ShouldAllHaveNonceAttribute(); // check for nonce attribute
    scripts.FromExternalOrigin // check all external scripts
        .ShouldNotBeEmpty()
        .ShouldAllHaveIntegrityAttribute()
        .ShouldAllHaveCrossOriginAttribute();
}

References

Clone this wiki locally