Verifying files used in deployment is an important security mechanism that prevents opportunistic attacker from introducing malicious files by manipulating a network connection or by swapping source file in a remote location. Those attacks are widespread and can result in great damages if malicious binaries are introduced to an internal company network. Ransomware, cryptominers or industrial espionage are the most common cases nowadays.
Security control proposal
There are various methods how to verify integrity of files downloaded either from untrusted sources or via untrusted network.
The most common methods for verification are:
- comparing cryptographic hash of a file with an expected one
- checking cryptographic signature of a binary
For the purpose o verifying binary, a third party must provide:
- a binary
- a public key corresponding to a private key with which the binary was signed
- a fingerprint of a binary (optionally a file with a fingerprint might be signed as well)
Comparing cryptographic hash of a file to a known one
Basic premise of this verification procedure is to create a cryptographic hash (fingerprint) by using widespread cryptographic hash function like SHA-256 and compare this cryptographic hash to a one provided by the publisher of the application.
It’s important to use cryptographic hash function as this family of hash functions provide collision resistance, which means, there is no easy way to construct a different file or binary which result to a same hash.
Don’t use weak cryptographic hash functions like MD5 or SHA-1. Those hash functions are broken so it’s possible to find different input that will result to the same hash output. Use current industry standard like SHA-256/512, Keccak or RIPEMD-160.
Note that obtaining known valid cryptographic hash could be a hard problem as its not always available.
There are alternative methods to validate an unknown file with some probability, like producing a cryptographic hash and checking it with the external reputation system like virustotal.com.
# download file wget https://example.com/file.bin # check if hash match expected one echo "80d6a5c972f933406c4de99ef2d960b4f7e0691257a373d8908ac46017730547 file.bin" | sha256sum -c - # continue processing file...
# download file RUN wget https://example.com/file.bin SHELL ["/bin/sh", "-o", "pipefail", "-c"] # check if hash match expected one RUN echo "80d6a5c972f933406c4de99ef2d960b4f7e0691257a373d8908ac46017730547 file.bin" | sha256sum -c - SHELL ["/bin/sh", "-o", "pipefail", "-c"]rootcax1.crt # continue processing file...
Checking cryptographic signature of a binary
- Download developer signing key and check if key fingerprint is the same as the one published by developer (on webpage, Github, …):
wget https://application.developer.example.com/signing.asc cat signing.asc | gpg --import-options show-only --import
- Import developer signing key to a GnuPG keyring:
gpg --import < signing.asc
Alternatively you can import key from keyserver:
gpg --keyserver keyserver.example.com --recv-keys <publisher-public-keyid>
- Download the application you want to use:
wget --continue https://example.com/file.bin
- Download signature file for your signed application:
- Verify application binary against the signature file:
gpg --no-options --keyid-format long --verify file.bin.sig file.bin