TOFU: Do You Check?
cedwards.xyz
cedwards.xyz
Secondly, I just wanted to say that there is an interesting side-effect to everything covered in that blog that effectively leads to a gap in most people's mental models (or maybe just mine). Because of the way these systems were defined/the way people interact with them, there are several conundrums when a large centralized host needs to deprecate an old key.
If a key were suspected of being compromised, it seems obvious that you could just stop serving the old key and tell all of your users to be prepared to re-TOFU. However, since _most_ devs blindly type "yes" when interacting with a large git host, this effectively primes the pumps for any bad actor that have MITM control but have not actually stolen the keys. This gives them a relatively long (if not infinitely long) window of time where a user will not be surprised to see "the prompt" and blindly accept trust of a host that could be controlled by the bad actor. If a key was completely successfully compromised by a bad actor, and said bad actor had MITM control of the victim network, then requests with the _old_ key would never actually reach the correct host and just quietly continue working (assuming the bad actor was savy enough to setup a remote system to properly behave as a git host without a prior copy of the target repository).
Damned if you do, damned if you don't, so always carefully TOFU.
Also,not sure why the author linked off to a Bitbucket Cloud blog post for the SSH keys, they are documented here[1] along with our recommended best practices WRT TOFU.
1 - https://support.atlassian.com/bitbucket-cloud/docs/configure...
How are you guys tackling host key rotation? Do you do it periodically, or on compromise? How do you protect such an important set of keys?
[0] https://bitbucket.org/blog/ssh-host-key-changes
edit I see eichin also linked to the same page
Didn't work, because there's no trailing newline on the output of site/ssh. So even if it works, it corrupts the next addition.
curl https://bitbucket.org/site/ssh >> ~/.ssh/known_hosts
To this: (curl https://bitbucket.org/site/ssh; echo) >> ~/.ssh/known_hostsOr turn on the option for ascii art keys.
However, that isn't true for "public" SSH endpoints, such as github, gitlab etc - e.g. if the attacker is impersonating the wifi if the nearest Starbucks to snoop on all the hipster solo-devs there, he'll probably be unable to impersonate github, because even people who use that wifi for the first time have probably connected to github before, on a different network.
Would they? Or would the person just delete the old key from their ~/.ssh/known_hosts and accept the new one?
When designing or evaluating security, one should not ignore that this is a part of reality.
I agree that "automatic trust on first use" is "good enough" for most cases and people (especially with sshfp records), and to be honest I think the warning you get once that fails is strong enough:
% git clone git@github.com:madmurphy/libconfini.git
Cloning into 'libconfini'...
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
Please contact your system administrator.
Add correct host key in /home/martin/.ssh/known_hosts to get rid of this message.
Offending ED25519 key in /home/martin/.ssh/known_hosts:118
Host key for github.com has changed and you have requested strict checking.
Host key verification failed.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
It's a strong warning, with a manual fix that's more than "just press ok" (probably intentionally), and if you choose to ignore that then that's your problem.I'm not really sure what could be done better? A centralized https-like system comes with its own downsides.
(The only complaint is that last "Please make sure you have the correct access rights and the repository exists" line, which is from git and not ssh, and a tad confusing; maybe it's possible for git to do better here?)
WARNING: Remote host identification has changed.
If you did not expect this, verify this change with the remote system administrator before proceeding.
Ideally the message should be able to be customized so that organizations who provision computers for their employees could include e.g. the phone number or email address for the internal help desk.https://salsa.debian.org/ssh-team/openssh/-/blob/master/debi...
After a while I sat back and thought to myself "is this really worth the cost in time?" And I concluded that no it wasn't. Plenty of people run scanners looking for bad stuff online, ranging from poisoned SSH to supply chain attacks on OSS. These are the people that find the baddies and the baddies eventually get targeted. Me as a lowly developer is just not spending time fruitfully by checking github.coms SSH fingerprint. It would be better if I scanned the web app that I'm working on for, say, SQL injection bugs or misapplied CORS headers or whatever else.
Ultimately security checks are an economic activity. The likelihood you are targeted via a given threat, the payoff to the attacker if you are targeted, the downside to the attacker if they are caught, etc. I think being realistic is prudent.
... and when you don't you drive up the probability of enabling the 4-stage attack that leaks private keys to Chines govt. Of course the probability is only 0.01% and it's worth to spend time on something better. And when you do check and other 1000 devs in the organization don't, what's the point, right?
This is how this stuff happens and we all read a nice post morten here somewhat 2 years later.
If it's so important to validate then it shouldn't be left up to a human to choose, it should be mandatory - but the process needs to be straightforward. Why isn't there a built in tool that we can trust to check for us when these alerts happen? Or at least streamline the process and provide certainty
And as for "SSH has no forward secrecy", I thought SSH used Diffie-Hellman or similar to derive the session key? The SSH host key (and the client's public key) is for authentication only, stealing them does not reveal anything about past sessions.
Isn't the most common way of identifying ssh clients still just public key authorization? Meaning the attacker can MITM the real client connecting to the server, satisfy the real client's request, and then likely carry on doing whatever it likes.
edit: actually no - I can see where my intuition is wrong (out of date from the time of widespread password auth). If the ssh server only accepts input that's been effectively signed by the authentication key, then there's no way for the MITM to send its own requests. Yet another reason to not use password auth.
What? This is not right, not even for the obsolete v1 ssh: https://utcc.utoronto.ca/~cks/space/blog/tech/SshForwardSecr...
Perhaps more people would check it if the usability was improved...
The original SSH threat model allowed for MITM, so you’d have to also allow for that happen to the SSH key distribution URI.
Context is key, it’s an interesting trade-off
Which is something OpenSSH already supports.
You can get an ASCII graphic for the host key with the VisualHostKey option. For example:
ssh -o VisualHostKey=yes tty.sdf.org
Alternatively, you can set this option permanently in the SSH client configuration like this: echo VisualHostKey yes >> ~/.ssh/config
ssh tty.sdf.org
Here is an example output: $ ssh -o VisualHostKey=yes tty.sdf.org
Host key fingerprint is SHA256:ZjwbO7AU8rHJExYrmZS2LqGZ7WfdoELfMrF54W92PYA
+--[ED25519 256]--+
| ... |
| .oo o |
| .=.* |
| . .* B |
| = o O S. |
|+ + o.o*E=. |
| o o O.++ o |
| o X = +.. o |
| + + +.. . |
+----[SHA256]-----+
user@tty.sdf.org's password:
This graphic looks like a pigeon to me. Similarly, the one for github.com looks like a cat to me. For each server I connect to via SSH I know what the ASCII art for the host key looks like. This familiarity aids in performing TOFU in a hassle-free manner.And the reality is: "No."
https://www.usenix.net/system/files/login/articles/105484-Gu...
Personally I always manually check on first use, but I agree this puts me in a small minority.
I said something similar in a comment last year. [0] It's unfortunate that the term TOFU is ambiguous. In practice it's used to refer to check on first use and blindly assume it's ok on first use.
If I've got suspicions about the network connection I'm on, I'll first ask him some questions about our adventures years ago, that nobody else would likely know about.
And one time when the host key changed, and I wasn't expecting it, he said my call was how he knew he replaced the right box. Tongue-in-cheek, but only barely.
The only time I immediately dismiss the key-changed message is when I'm cycling yet another raspberry pi image into the same IP as an old one or whatever, and I'm on the local network so I know exactly what's going on.
If I have to connect to a new machine, I identify it by its hostname, and send it my credentials (whatever credentials the owner just sent me in plaintext).
If I get the warning and I'm pretty sure I connected to this machine before, I ask whoever owns the machine "hey did you do something weird with this machine? Like reimage it or rotate SSL certs or change the DNS entry so it's actually a different machine?"
99% of the time I'm not connecting to a machine for the first time, so (if I may be allowed some bad maths) this reduces my attack surface by a factor of 100.
(If the owner didn't send me plaintext credentials but instead added my SSH key, I don't expose anything by using that, but I immediately follow up by doing other sensitive things like scp'ing code or credentials there).
"I dunno."
But I've certainly been guilty of just hitting "yes" on first connection to a machine I'm unfamiliar with.
Before SSH host certificates, using tooling like ansible was seriously annoying, especially to the monthly ansible users, compared to the daily ansible users. If you tried using ansible once a month without our host key certificates, you'd have ansible barf about a dozen unknown host keys due to them being rebuilt and other things. Then you fix that, then they do that one ansible run, then it lies around for a month and back you go to square one.
I'm not sure HOW you'd stage an actual attack there, but people got used to just accept SSH host keys whatsoever, so the vulnerability was there.
Now we have host key signing based on Vault. This is a huge improvement in my book. Base infra guys know when they've reset a VM to a base image (which resets SSH host keys), so they know when to expect a TOFU request from their SSH upon first connect to the just rebuilt system, so they accept those. Afterwards, one of the first things the config management does is to sign those host keys and then the accepted host keys are usually deleted again.
There probably is a window of vulnerability in there, but that's getting pretty hard to attack and I'm sure there are easier ones in the overall infrastructure.
The main problem at this however is that you need some safe and secure place for the CA, and ideally automation to sign those host keys. And it needs to be enough of a problem to do all of that.
The only exceptions I make are video conferencing and email. Jitsi provides great end-to-end encryption for the former (although the 8x8 server's recent prohibition of anonymous use is disappointing).
This is not just about secrecy, but also about integrity. Someone who MITMs your connection could not only look at the code you published, but also modify it. Then later someone who was trusting you (or possibly even yourself on a new machine) will end up downloading and running the modified code.
More importantly, in my opinion, the end-user has no way of verifying the integrity of the code if authentication was the only security measure. By signing releases or the commits themselves (which can be done with both PGP and SSH keys currently) the end-user can verify the integrity themselves.
I can understand not expecting every user to do a one-time 10-second diligence process. But the "enterprise" provider seemingly not expecting any of its customers' IT people to even do a one-time 10-second check when integrating mission-critical infrastructure... is a concern.
What am I doing on a network I don't trust with a machine I've never used? The example given is that I've started a new job. Well okay, their machine, their network, and I guess their corporate gitprovider.net account they're getting me to use, so to heck with it.
If we're talking about using _my_ gitprovider.net account however, that's a different story. I simply wouldn't use my own account on a laptop that's not mine.
The solution is to use SSH Certificate Authentication as opposed to SSH Key Authentication. The Certificate has a forced expiry and is verified by a CA. Then interception is rendered a moot problem since keys are verified with the CA before use.
Slack message at 3pm asking for updates to be in a doc by 6pm. What do you expect?
I guess the problem is less serious on a corporate VPN, but still, the principle applies everywhere. If you want security, give your employees time to do things right. Usually that means at least double what you think it will take.
Of course, to really have Zero Trust you have to make it impractical for users to "yes" through the dialog.
Seems like too much work for checking the fingerprints if not in an obvious security first context.