HTML Script Integrity Attribute – SubRresource Integrity (SRI)

What is integrity attribute?

You might have seen the integrity attribute as well as crossorigin attribute in web page source code. The integrity and crossorigin attributes are used in the <script> and <link> tags. This is also called subresource integrity because it is included into the third party resources which are parts of the HTML pages.

An integrity attribute’s value begins with a hash algorithm (any one of sha256, sha384, sha512), followed by a dash (-) and ending with an actual base64-encoded hash value.

For example, sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo, where, sha384 is the prefix or algorithm and q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo is the actual hash.

The subresource integrity (SRI) is a new specification to protect third party resources from unexpected manipulation and used mainly for the third party hosted resources, JavaScript, jQuery, CSS, fonts, etc.

Browser also does another security check by CORS (Cross Origin Resource Sharing) to ensure the origin sharing the resource is allowed to be loaded by the browser in the request origin.

Why do you need SRI?

Let’s say your web pages use third party jQuey or JavaScript files or style sheet files (css) or fonts. So, basically these third party resources which you use are not hosted in your server where your web application is running. Therefore, you are using CDN (Content Delivery Network) link to include these third party resources.

Using third party resources or hosting scripts and stylesheets in different servers will improve performance and conserve bandwidth but it also comes with a risk.

An attacker may try to inject the malicious content into the third party resources (or change the content completely) though your web site uses connection over HTTPS using TLS.

TLS ensures that the connection between your browser and server is secure but it won’t ensure the integrity of your third party resource content yet content will be served with valid TLS certificate.author

On the other hand, SRI (subresource integrity) ensures that a resource has not changed its content because SRI uses a hash generated by a web author. This hash value is basically a base64-encoded cryptographic hash of the file or resource. This hash value is specified in the integrity attribute of the script or link element.

crossorigin=”anonymous” attribute

You must include the crossorigin attribute to check the integrity of the resource when the resource is not hosted on the same origin server where your web application is hosted. Without crossorigin attribute, the browser will load the resource as if the integrity attribute was not set, effectively losing all the security SRI brings in.

crossorigin="anonymous" means that no credential is sent to the cross-origin site where your application’s third party resource is hosted. However, the Origin will be sent in the HTTP header and if the server denies the resource then the resource will not be used by the browser.

SRI(Subresource Integrity) Generations

There are several ways one can generate SRI, such as, using any programming language or even using CLI in Unix based system.

To generate SRI values for a file you can use the following command in shell terminal:

$ openssl dgst -sha384 -binary FILENAME.js | openssl base64 -A

Make sure you cahnge the FILENAME.js with actual file name in the above command.

I will show you here how to generate the SRI using PHP and Java programming languages.

The sample JavaScript file (sample.js) is used for this example. The content of this file is given below:

// program to check a number is prime or not
 
// get input from the user
const number = parseInt(prompt("Enter a positive number: "));
let isPrime = true;
 
// check if number is equal to 1
if (number === 1) {
    console.log("1 is neither prime nor composite number.");
}
 
// check if number is greater than 1
else if (number > 1) {
 
    // looping through 2 to number-1
    for (let i = 2; i < number; i++) {
        if (number % i == 0) {
            isPrime = false;
            break;
        }
    }
 
    if (isPrime) {
        console.log(`${number} is a prime number`);
    } else {
        console.log(`${number} is a not prime number`);
    }
}
 
// check if number is less than 1
else {
   console.log("The number is not a prime number.");
}

SRI Generator – Java Program

Here is the following code that generates SRI hash for the above sample.js file.

public class SriHashGeneratorApp {

	public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
		String sri = generateSriHash(new File("src/main/resources/sample.js"), Algorithm.SHA256);

		System.out.println("SRI 256: " + sri);

		sri = generateSriHash(new File("src/main/resources/sample.js"), Algorithm.SHA384);

		System.out.println("SRI 384: " + sri);

		sri = generateSriHash(new File("src/main/resources/sample.js"), Algorithm.SHA512);

		System.out.println("SRI 512: " + sri);
	}

	public static String generateSriHash(File file, Algorithm algorithm) throws IOException, NoSuchAlgorithmException {
		byte[] data = Files.readAllBytes(file.toPath());

		MessageDigest digester = MessageDigest.getInstance(algorithm.getCode());
		digester.update(data);

		return Base64.getEncoder().encodeToString(digester.digest());
	}

}

I have used all three algorithms (sha-256, sha-384 and sha-512) to generate SRI hash. You can use any one of the alogorithms to suit your requirements.

Running the above program you will see the following SRI values for sample.js file:

SRI 256: JsGvJEABFkVPHt/WrnH9xHazI+/xbk99DFETy/m/txk=
SRI 384: 6PA3dWY94hYG72z79qZQuiFTqmHuQD4URq1sK1mEpBHsn4BbubkvG0dCHPz9uvL9
SRI 512: eD1q1Z5vPBq6nUGXpAfdMV+K4Wy0lOvYxo3B7zhcr8GBTG92sobeQdjTBHq3rqSZ1pE3LW5mTZD+0Ocf1j7y4g==

SRI Generator – PHP Program

The following PHP program shows how to generate SRI hash. Notice that I have used two different functions to generate hash values – using hash() and openssl_digest() functions.

<?php
 
	$file = file_get_contents("sample.js");

	echo generate_sri_hash($file, 'sha256');
	echo "\n";
	echo generate_sri_hash($file, 'sha384');
	echo "\n";
	echo generate_sri_hash($file, 'sha512');

	echo "\n\n";

	echo generate_sri_openssl($file, 'sha256');
	echo "\n";
	echo generate_sri_openssl($file, 'sha384');
	echo "\n";
	echo generate_sri_openssl($file, 'sha512');

	echo "\n";


	function generate_sri_hash($file, $algo = 'sha256') {
	  return base64_encode(hash($algo, $file, true));
	}

	function generate_sri_openssl($file, $algo = 'sha256') {
	  return base64_encode(openssl_digest($file, $algo, true));
	}
?>

Running the above program you will see the following SRI values:

JsGvJEABFkVPHt/WrnH9xHazI+/xbk99DFETy/m/txk=
6PA3dWY94hYG72z79qZQuiFTqmHuQD4URq1sK1mEpBHsn4BbubkvG0dCHPz9uvL9
eD1q1Z5vPBq6nUGXpAfdMV+K4Wy0lOvYxo3B7zhcr8GBTG92sobeQdjTBHq3rqSZ1pE3LW5mTZD+0Ocf1j7y4g==

JsGvJEABFkVPHt/WrnH9xHazI+/xbk99DFETy/m/txk=
6PA3dWY94hYG72z79qZQuiFTqmHuQD4URq1sK1mEpBHsn4BbubkvG0dCHPz9uvL9
eD1q1Z5vPBq6nUGXpAfdMV+K4Wy0lOvYxo3B7zhcr8GBTG92sobeQdjTBHq3rqSZ1pE3LW5mTZD+0Ocf1j7y4g==

Notice the Java and PHP programs produced exactly same SRI values.

Source Code

Java Code

PHP Code

Leave a Reply

Your email address will not be published. Required fields are marked *