Generating a CSP Hash at the CLI

Published: April 17, 2020

Tags:

I’m currently attempting to set up a Content-Security-Policy on this site in strict-dynamic mode. As this is a static site, nonces are not an option for me, so I’m looking into using hashes. I was pulling my out hair earlier this evening trying to figure out how to generate the hashes in the correct CSP format at the command line. I finally figured it out piecing together various bits of information and wanted to share my findings here.

If You Just Want The Answer

This blog post will tell the story and explain what’s going on. If you’re not interested in all I’m putting the answer up front:

$ echo -n 'alert(1);' | shasum -a 256 | cut -d' ' -f1 | xxd -r -p | base64
5jFwrAK0UV47oFbVg/iCCBbxD8X1w+QvoOUepu4C2YA=

If you want to know more, please continue to read

ReportURI’s Web UI

ReportURI offers a nice web-based tool for generating CSP hashes.

Here’s a screenshot of the output for alert(1);

Screenshot showing value of alert(1); hashing to 5jFwrAK0UV47oFbVg/iCCBbxD8X1w+QvoOUepu4C2YA= using ReportURI hasher

As you’d expect, the tool generates the hashes correctly.

Doing it at the CLI - First Try

Per MDN’s script-src documentation we need to generate a “base64-encoded hash”

At first glance that seems like it shouldn’t be too bad. This is what I initially came up with:

$ echo -n 'alert(1);' | shasum -a 256 | cut -d' ' -f1 | base64
ZTYzMTcwYWMwMmI0NTE1ZTNiYTA1NmQ1ODNmODgyMDgxNmYxMGZjNWY1YzNlNDJmYTBlNTFlYTZlZTAyZDk4MAo=

However, as you’ll notice by comparing against the output from ReportURI, this is not the expected value.

Digging Deeper

After a bit more research I found another web UI that generates CSP hashes. This one also provided the following example PHP source code for generating CSP hashes:

<?php
$algo = 'sha256';
$data = "console.log('Hello World');"; # This is your inline JS/CSS without the <script>/<style> tags
$base64 = base64_encode(hash($algo, $data, true));
echo "$algo-$base64";
# sha256-4saCEHt0PuLiuYPF+oVKJcY5vrrl+WqXYIoq3HAH4vg=
?>

The thing that caught my eye here was the third argument being passed to the PHP hash function. Per the PHP documentation:

When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.

https://www.php.net/manual/en/function.hash.php

A-ha! shasum wasn’t outputting raw binary data, but instead a hex representation.

From what I could tell from shasum’s man page, there’s no option to output as binary, however this StackExchange answer gave me the idea to use xxd.

The below command ultimately generates the hash in the correct format for usage in a CSP.

$ echo -n 'alert(1);' | shasum -a 256 | cut -d' ' -f1 | xxd -r -p | base64
5jFwrAK0UV47oFbVg/iCCBbxD8X1w+QvoOUepu4C2YA=

Max Chadwick Hi, I'm Max!

I'm a software developer who mainly works in PHP, but also dabbles in Ruby and Go. Technical topics that interest me are monitoring, security and performance.

During the day I solve challenging technical problems at Something Digital where I mainly work with the Magento platform. I also blog about tech, work on open source and hunt for bugs.

If you'd like to get in touch with me the best way is on Twitter.