DEV Community

Orkhan Huseynli
Orkhan Huseynli

Posted on

18 5 4 4 3

Verifying Integrity of Files using NodeJS

While using third party JavaScript or CSS libraries from CDN, you've probably came across with integrity attribute on script or link tags.

<script 
  src="https://code.jquery.com/jquery-3.6.4.min.js" 
  integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" 
  crossorigin="anonymous">
</script>
Enter fullscreen mode Exit fullscreen mode

If you haven't researched about them till now, then you're in the right place.

Man in the Middle Attacks

It's possible that the any data which travels through internet can be modified till it reaches to our machine. An attacker might use techniques such as network eavesdropping to intercept the requests and responses between you and the server and might manipulate the file before you even receive it.

We need a way to verify that the file we've received has not been tempered with.

Subresource Integrity in Browsers

Browsers implement a security feature called Subresource Integrity (SRI) to verify integrity of the resource they fetch and execute.

The garbage looking string of characters you see as the value of integrity attribute is Base64 decoded cryptographic digest formed by applying specific hash algorithm to the contents of the file.

If any characters inside the file changes, then the calculated hash will also change, thus integrity verification will fail, thus the browser will know that the file has been tempered with.

If browsers cannot verify integrity of the file being requested, they'll show error message similar to this:

Failed to find a valid digest in the 'integrity' attribute 
for resource '<resource-name>' with computed SHA-256 integrity '<calculated-hash>'. 
The resource has been blocked.
Enter fullscreen mode Exit fullscreen mode

Performing Integrity Check with NodeJS

To show a little demo how this check might be implemented, I'll use NodeJS's crypto module. We'll use the same jquery file the you saw in the first paragraph. I'll download that file into my machine to be able to make modifications later.

Let's create an index.js file and import fs and crypto modules:

import crypto from 'crypto';
import fs from 'fs';
Enter fullscreen mode Exit fullscreen mode

We'll need fs module to read contents of the file that we want to verify integrity of. Let's declare resource name and expected integrity:

const resource = 'jquery-3.6.4.min.js';
const expectedIntegrity = 'oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=';
Enter fullscreen mode Exit fullscreen mode

Note that sha256 in front of the value of integrity attribute is just the name of hashing algorithm that this hash has been calculated with, so we skip it when comparing.

Let's read the file contents and calculate the digest using sha256 algorithm:

const jquerySource = fs.readFileSync(resource);
const digest = crypto
  .createHash('sha256')
  .update(jquerySource, 'utf8')
  .digest();

const calculatedIntegrity = digest.toString('base64');
Enter fullscreen mode Exit fullscreen mode

The value of digest variable is a type called Buffer which is just bunch of bytes, so we need to convert it to a string in base64 encoding.

And finally, we just need to compare calculatedIntegrity with expectedIntegrity, if they are equal then the jquery-3.6.4.min.js has not been tempered with, if not, it means something has changed inside the file:

if (calculatedIntegrity == expectedIntegrity) {
  console.log('✔️ Resource integrity verified!');
} else {
  console.log(`❌ Failed to find a valid digest in the 'integrity' attribute 
  for resource '${resource}' with computed SHA-256 integrity '${calculatedIntegrity}'.`);
}
Enter fullscreen mode Exit fullscreen mode

If you run this code using node index.js then, you might see this output:

$ node index.js
✔️ Resource integrity verified!
Enter fullscreen mode Exit fullscreen mode

Now, if you change the contents of jquery-3.6.4.min.js file, and run the code again, then you'll see output similar to this:

$ echo 'some malicious code' >> jquery-3.6.4.min.js
$ node index.js
❌ Failed to find a valid digest in the 'integrity' attribute 
  for resource 'jquery-3.6.4.min.js' with computed SHA-256 integrity '+FiqKbj0h12Db1PZj62G+h2BMtOueBg26YQOJFY+6wg='.
Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope this article was helpful for you, I suggest you read more at article at Smashing Magazine about Subresource Integrity and share your thoughts.

You can see the full version of the code we wrote at my GitLab repository.

Tiugo image

Modular, Fast, and Built for Developers

CKEditor 5 gives you full control over your editing experience. A modular architecture means you get high performance, fewer re-renders and a setup that scales with your needs.

Start now

Top comments (0)

Neon image

Next.js applications: Set up a Neon project in seconds

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Get started →

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay