-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: User-provided hash #3349
Comments
Where are you getting the hash from in the first place if you can't trust nodejs.org? |
nodejs.org, probably. TOFU (trust on first use) is imperfect, but it's better than not having a hash at all. What hard-coding the hash buys me is that in order to remain undetected, an attacker would then need to MITM me (and everyone else running my code, and my CI server) consistently, every single time, without changing the payload. If the hash does not appear in my code, an attacker can (for instance) focus on only CI. They can inject their malicious version of nodejs once, wait for it to phone home, and then once they have established that the attack is viable they can iterate on it... each time injecting the newest version of the malicious payload. They can change it and remain undetected, so long as they don't break it. I don't know how many threat actors exist which can pull off this kind of attack at all, probably some, but even fewer are those that can pull it off consistently enough to fool every target every time, which would be necessary to remain hidden in the case where the hard-coded hash was actually the malicious one. I ended up just getting node from `https://nodejs.org/dist/v16.13.2/node-v16.13.2-darwin-arm64.tar.gz" and hard coding its hash like so. If you suspect that nobody beside me cares, it might be sensible to close this. I'd love it if my paranoia turned out to be unfounded. |
I mean, nvm could certainly start caching the hashes, and report when they change - but sometimes they DO change, for legitimate reasons. The purpose of checking the hash is to ensure the download isn't corrupted - it doesn't protect you against MITM, that's what SSL is for. |
The purpose of hard coding a hash is to ensure that if/when an input changes, you're made aware of it because the hash check fails. Forget the security stuff for a moment, that kind of awareness is useful for puzzling out causes and effects. If something suddenly breaks, and only one of its inputs has changed since the last time it succeeded, then you know what to scrutinize. I'm aware that this degree of scrutiny is not customary for the nodejs world, which likes to resolve things at runtime and not build time, I just sometimes wish it was 😅. |
Do you think a hardcoded sha on the command line is necessary? or would it work if nvm cached the sha for a version on first sight - and then refused to install if the sha differed, but then telling you how to manually override and accept the new sha? |
The scenario which prompted this issue is that I encountered a failure in CI where we had piped from data from http to bash, but bash was failing because it was attempting to run an http error response as if it was a shell script. The thought was:
My favored solution for this is nix, which collects hashes for all of the project dependencies into a - http get https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
+ http get https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | save nvm.sh
+ # exit nonzero if hash doesn't match
+ cat nvm.sh | hash sha256 | grep 8e45fa547f428e9196a5613efad3bfa4d4608b74ca870f930090598f5af5f643
+ cat nvm.sh | bash I'm afraid that the hardcoded sha can't be dispensed with entirely, because I still have to worry about whether nvm itself has changed. But the root of this issue is that the above approach is no good for nvm anyhow because even though I may have guaranteed that I'm getting an unchanged I could imagine doing something like this on my dev machine:
And then this might happen in CI
I feel a little silly troubling you with this, especially since I've already moved on from using nvm anyhow. Your time is precious, thanks for taking some of it to listen to me. |
For a hash of nvm itself, it's fetched from github, you can fetch it by git SHA, and github is using SSL cert pinning, so github itself would have to be compromised for this to be a concern worth spending even 10 minutes of time solving. So, it sounds like the reasonable path left would be for nvm to auto-cache SHAs from nodejs.org's index.tab on first sight, and if any sha has changed, to fail loudly, and tell the user to run a command (like |
What you're describing would scratch my itch 😄 In order to benefit from this in CI, users would have to teach CI about the cache file. Proceeding without thinking about it would lead to a case where the cache was empty every time. But I think that might be a necessary evil in this case. Another potential misstep: a user commits their cache file, generated on one system architecture, but their CI uses a different architecture. They don't see the loud failure, so they assume that the file has not changed, but actually it was a cache-miss due to the architecture mismatch, and the file has changed. To avoid this I'd suggest adding a cli arg or an env var which would disable quietly updating the cache on a miss. |
i'm confused - if a hash isn't in the file, then it doesn't matter whether it changed or not. are you saying that you want an option to fail loudly if you haven't pre-cached the hash? |
Yes that's what I'm suggesting. It would be analogous to how The goal would be to avoid cases where a user is unaware that a difference in the nodejs artifact has subsequently caused a difference in behavior. Without a In such a case It's easy to believe that things are deterministic, when in fact you're just getting lucky because the package source happens to be unchanging at this time. If this happens, you're in for a surprise later when the package either changes authentically and breaks things by accident (more likely), or when you get MITM'd and now it contains malware (less likely). In either case, the problem is easier to identify if it fails earlier in the chain. |
I see that nvm checks nodejs versions against a copy of SHASUMS256.txt which it downloads from the same mirror that it downloads nodejs.
This verification is not without value as-is, but I've got my tin-foil-hat on and it doesn't quite scratch the itch. I'd like to hard-code a hash so that my automation will break if there's a MITM between myself in the mirror (otherwise the MITM can just tamper with SHASUMS256.txt to make the verification pass and hide whatever skulduggery they've amended node with).
I'm imagining something like:
Please consider it. Thank you.
The text was updated successfully, but these errors were encountered: