securl - curl with SHA-256 integrity validation
A case study
Let’s say I found this super cool script on the Internet somewhere. It “totally works on my machine”, so, I can confirm it’s not malware. I document on my website how to download and run it:
curl https://example.com/cool.sh | bash
The problem is, even if you trust me, how do you know link hasn’t changed since I wrote about it? How do you know the host hasn’t replaced it with some other script, or that the site hasn’t since been infiltrated by hackers? You don’t. But, people take these chances every day.
A long-known solution is to manually verify cryptographic hash of the file. Historically, what people have done is post the SHA-256 checksum on the footer of their page, and ask their users to nicely perform a comparison.
Instead, you could use securl
.
securl to the rescue
To download the same file using securl
, you could run:
seccurl https://example.com/cool.sh#9hDLTsDb7SGMVunRSrP6zA2c1wmvWawX4 | bash
Notice I’ve just tacked on #9hDLTsDb7SGMVunRSrP6zA2c1wmvWawX4
at the end: the part after the #
was the hash of the file when I linked to it. Appending a URL anchor (#
) usually works seamlessly without any action taken by the file server.
What happens is that securl
will only download the file if its hash is embedded within the originating hyperlink URL. (In fact, securl
will be happy if the hash is anywhere inside the URL.) Otherwise, if the hash fails to match, it will refuse to output any part of the file (and will also show you what the actual hash was).
How to install securl
To download and install securl
securely, run:
securl https://raw.githubusercontent.com/notfed/securl/master/securl#9ff1gWE1c1vDaoTrwZyWcLtSvo8ap2S69 | sudo cp /dev/stdin /usr/local/bin/securl
Oh, wait, you don’t have securl
. To download and install it insecurely, run:
curl https://raw.githubusercontent.com/notfed/securl/master/securl | sudo cp /dev/stdin /usr/local/bin/securl
Or, see GitHub.
About the hash format
For securl
, the format of the hash is a base58-encoded SHA-256 hash of the file truncated to 192 bits. (This is in contrast to SHA-256/192, which I did not use for purposes of portability/simplicity/laziness.)
This keeps the hash short (33 characters) while still offering 96 bits of security. (For an attacker to break this system, they would not only need to perform roughly $\frac{2^{96}}{2}$ operations, but would also need to find a way to compromise the file server and/or transport security.)