HTML - HTML Subresource Integrity (SRI)

 

1. Introduction to Subresource Integrity

Subresource Integrity (SRI) is a web security feature that allows browsers to verify whether an externally hosted JavaScript or CSS file has been modified unexpectedly. It helps protect websites against certain attacks in which a third party changes a file hosted on a content delivery network (CDN) or another external server.

Modern websites often load resources from external sources to improve performance and simplify maintenance. For example, a website may load a JavaScript library from a CDN instead of storing a local copy on its own server. Although this can be convenient, it creates a security risk if the external resource is compromised.

SRI addresses this risk by allowing the developer to specify a cryptographic hash of the expected file. The browser downloads the resource, calculates its hash, and compares the result with the hash specified in the HTML. If the values do not match, the browser refuses to use the resource.

SRI is primarily used with external JavaScript files included through the <script> element and CSS files included through the <link> element.

2. Why Is Subresource Integrity Important?

When a website depends on an external resource, it also depends on the security and integrity of that resource. If an attacker compromises the external server, the attacker might replace a legitimate JavaScript file with malicious code.

For example, suppose an online shopping website loads a JavaScript library from a third-party CDN. If that library is modified to capture payment information or alter the checkout process, visitors could be exposed to serious security risks.

Without an integrity check, the browser may execute the modified JavaScript file as if it were legitimate. With SRI, the browser checks whether the downloaded file matches the expected cryptographic hash.

The main benefits of SRI include:

  • Protection against unexpected modifications: Helps prevent browsers from using altered external scripts and stylesheets.

  • Improved supply-chain security: Reduces the risk associated with compromised third-party resource hosting.

  • Integrity verification: Allows developers to specify the expected contents of a resource.

  • Additional security for CDN resources: Provides another layer of protection when websites use externally hosted libraries.

SRI does not replace other security measures. It works alongside HTTPS, Content Security Policy (CSP), secure development practices, and regular dependency updates.

3. How Does Subresource Integrity Work?

SRI works through a process of generating, specifying, and checking a cryptographic hash.

The process can be understood in four steps.

  1. Generate a hash: The developer calculates a cryptographic hash of the original JavaScript or CSS file using an algorithm such as SHA-384.

  2. Add the hash to HTML: The developer places the generated hash in the integrity attribute of the relevant HTML element.

  3. Download the resource: When a visitor opens the webpage, the browser requests the external file.

  4. Verify the resource: The browser calculates the hash of the downloaded resource and compares it with the expected hash. If verification succeeds, the resource can be used. If verification fails, the browser blocks it.

For example, if the original JavaScript file contains legitimate code but someone modifies even a small part of it, its cryptographic hash will normally change. The browser detects the mismatch and rejects the resource.

4. The integrity Attribute in HTML

The integrity attribute is the main HTML attribute used to implement SRI. It specifies the expected cryptographic hash of an external resource.

Consider the following example:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SRI Example</title>

    <script
        src="https://cdn.example.com/library.js"
        integrity="sha384-REPLACE_WITH_REAL_HASH"
        crossorigin="anonymous">
    </script>
</head>
<body>
    <h1>Subresource Integrity Example</h1>
</body>
</html>

In this example, the HTML document loads an external JavaScript file.

The src attribute specifies the location of the JavaScript file. The integrity attribute specifies the expected cryptographic hash. The crossorigin="anonymous" attribute enables the appropriate CORS-based request behavior required for cross-origin SRI verification.

The example uses a placeholder hash, so it will not work as written. A real hash generated from the exact file must replace REPLACE_WITH_REAL_HASH.

The browser verifies the downloaded resource before allowing the script to execute. If the resource does not match the expected hash, the browser blocks it.

5. Understanding the crossorigin Attribute

The crossorigin attribute controls how certain cross-origin resources are requested.

When using SRI with a resource hosted on another origin, the server generally needs to provide an appropriate CORS response. The HTML element must also use a compatible cross-origin request mode.

For example:

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

Here, crossorigin="anonymous" requests the resource without including cross-origin credentials such as cookies in the request. The remote server must provide the necessary CORS response headers for the browser to use the resource successfully.

The crossorigin attribute does not itself verify the file. Integrity verification is performed using the hash in the integrity attribute.

6. Cryptographic Hash Algorithms Used in SRI

SRI supports cryptographic hash algorithms that allow browsers to identify changes in file contents.

The main supported algorithms are:

Algorithm

Description

SHA-256

Produces a 256-bit hash and offers a strong integrity check.

SHA-384

Produces a 384-bit hash and is commonly used in SRI examples.

SHA-512

Produces a 512-bit hash and provides a longer hash output.

SHA stands for Secure Hash Algorithm. A hash is a fixed-length value calculated from the contents of a file.

For example, if a JavaScript file is changed from:

console.log("Welcome");

to:

console.log("Welcome to the website");

the calculated hash will change. Consequently, the original hash specified in the HTML will no longer match the modified file.

SHA-384 is a practical choice for many SRI implementations. Developers should use a supported cryptographic algorithm and generate the hash from the exact resource that the browser will download.

7. Implementing SRI for an External CSS File

SRI is not limited to JavaScript. It can also be used to verify externally hosted CSS stylesheets.

Consider this example:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS Integrity Example</title>

    <link
        rel="stylesheet"
        href="https://cdn.example.com/styles.css"
        integrity="sha384-REPLACE_WITH_REAL_HASH"
        crossorigin="anonymous">
</head>
<body>
    <h1>Welcome to My Website</h1>
    <p>This page uses an external stylesheet.</p>
</body>
</html>

In this example, the browser checks the stylesheet against the specified hash before applying it.

If the stylesheet has been modified and its hash does not match, the browser rejects the stylesheet rather than applying potentially unexpected styles.

This is useful when a website uses external CSS frameworks, shared design libraries, or stylesheets hosted on a CDN.

8. How to Generate an SRI Hash

Developers must generate a hash from the exact version of the resource they intend to load. A hash should not be guessed or copied from an unrelated file.

One common method is to use the OpenSSL command-line utility.

For a JavaScript file named app.js, run:

openssl dgst -sha384 -binary app.js | openssl base64 -A

This command calculates the SHA-384 digest of the file and encodes the result in Base64.

The output can be added to the HTML with the algorithm prefix sha384-.

For example, if the command produces a Base64 value represented here as GENERATED_BASE64_HASH, the HTML attribute would look like this:

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

The displayed value is illustrative, not a valid hash. Developers must use the actual output generated from the resource they are loading.

Whenever the resource is updated, the hash must be regenerated and the HTML updated accordingly.

9. What Happens When SRI Verification Fails?

If a resource fails SRI verification, the browser blocks that resource from being applied or executed.

For example, imagine that a website specifies the correct hash for a JavaScript library. Later, an attacker modifies the library on the CDN to include malicious code.

When a visitor opens the webpage, the browser downloads the modified file and calculates its hash. Since the calculated value differs from the expected value, the browser rejects the resource.

This prevents the modified external script from executing through that script element.

Developers can inspect the browser's developer tools, particularly the Console and Network panels, to identify integrity verification errors.

However, SRI does not automatically repair the resource, replace it with a safe copy, or guarantee that the entire website is secure. The developer must investigate the problem and restore or update the trusted resource.

10. Limitations and Best Practices of SRI

Although Subresource Integrity improves web security, developers should understand its limitations.

Limitations

  • SRI does not protect every resource type. Its standard HTML integration primarily covers external scripts and stylesheets.

  • It does not protect a resource if the expected hash itself has been maliciously changed.

  • It does not prevent attacks involving malicious code already present in the trusted file.

  • It does not replace HTTPS, Content Security Policy, secure server configuration, or dependency management.

  • It can cause a resource to stop loading after a legitimate update if the HTML still contains the old hash.

  • Cross-origin SRI requires appropriate CORS support from the external server.

Best practices

  1. Use SRI for suitable external JavaScript and CSS resources, especially when they are hosted on third-party CDNs.

  2. Generate hashes from trusted, exact resource versions.

  3. Use HTTPS to protect resource delivery in transit.

  4. Update integrity hashes whenever the referenced file changes.

  5. Test resource loading after deploying integrity attributes.

  6. Use Content Security Policy as an additional layer of protection.

  7. Monitor browser-console errors and investigate unexpected integrity failures.

  8. Avoid automatically updating a resource without verifying its contents and updating its corresponding hash through a trusted release process.

Conclusion

HTML Subresource Integrity is an important web security mechanism that helps developers verify the integrity of external JavaScript and CSS files. By using the integrity attribute and a cryptographic hash, a developer can instruct the browser to reject a resource whose contents do not match the expected version.

SRI is particularly useful for websites that depend on third-party libraries and CDN-hosted resources. When combined with HTTPS, Content Security Policy, and careful dependency management, it helps reduce the risks associated with compromised external resources and strengthens the overall security of a website.