> By the way, did you know that GitHub publishes all users' ssh public keys and Ben (benjojo.co.uk) grabbed them all?
> That's pretty handy at times :) But not this time :(
>Better luck next time, I guess :)
Who cares if they publish Public Keys. They're meant to be public, it's one of the few well named things in computer science. They are basically meant to be spewn everywhere.
You can dos someone just by knowing their ip or how to get a hold of them. You can also sign up magazines to be delivered to their office address and DOS their workplace.
DOS is a bit of a misleading term here. You're not actually denying them service at all. You're just tricking the service provider into potentially mis-identifying them as a different user, depending on how their SSH is configured, and it's easily solved by a small SSH config change on their end. And it only works against someone who has multiple keys anyway.
> A simple solution would be to avoid the single user login git@service.com, and use that as identification, for example gmalette@service.com.
Except this completely ignores the reason why services use git@service.com. It's not because they're lazy. It's because the URL is supposed to identify the project, not the user. If the URL included the user's own username, that URL wouldn't work for anyone else, which breaks git-submodules, breaks any kind of config file that specifies repositories (e.g. for use by a CI server), and removes the ability for people to copy&paste a `git clone` command from a README (or blog post or wherever else).
So yes, there is a theoretical annoyance attack here, but nobody really cares because it's never going to happen accidentally, it can't be used against most people, and it's so trivially bypassed nobody's going to bother doing it except as a PoC. The benefits of using git@service.com greatly outweigh the downsides.
> and it's easily solved by a small SSH config change on their end
The article does mention it. The issue is not fixing the problem, it's actually finding it.
> [...] that URL wouldn't work for anyone else, which breaks git-submodules, breaks any kind of config file that specifies repositories (e.g. for use by a CI server)
It doesn't explain why Heroku uses it. Do you really push different submodules to Heroku?
For Github et. al, that's easily solved by project-level or organization-level identity.
> that URL wouldn't work for anyone else
And using `git@` doesn't work if you use multiple accounts because you'd specify the IdentityFile by host.
> nobody really cares because it's never going to happen accidentally
Except it does. Those service providers often get contacted because this happens BY ACCIDENT.
I've done it to myself by adding my public key to my work account. I couldn't access my personal stuff without changing my SSH config.
A while ago at work, we were using a shared key that was used to setup the initial vagrant config. New hires often added that key to their github or heroku account.
> It doesn't explain why Heroku uses it. Do you really push different submodules to Heroku?
I don't use Heroku, but, sure, why not? If I push a repo to Heroku that includes submodules, presumably Heroku then fetches those submodules (I'm assuming it supports submodules at all, which seems like an obvious thing to support). Therefore, those submodules must be specified by a URL that works for everyone, not just you.
> For Github et. al, that's easily solved by project-level or organization-level identity.
How does that solve anything? You're no longer identifying the user whose key is supposed to be used, which means this no longer solves your problem. And if you're going to suggest that it should only consult users who have access to the repo, for a public project that's everybody, which makes it functionally identical to git@.
> And using `git@` doesn't work if you use multiple accounts because you'd specify the IdentityFile by host.
Sure it does. IdentityFile is explicitly allowed to be specified multiple times for a single host, and the files will be tried in turn. So you can specify all your keys that way.
> Those service providers often get contacted because this happens BY ACCIDENT.
Someone uploads a private key that doesn't belong to them by accident, that screws up other innocent people? I'm rather skeptical. What's your source on this? And no, your own anecdotes do not constitute proof that providers often have to deal with this.
> A while ago at work, we were using a shared key that was used to setup the initial vagrant config. New hires often added that key to their github or heroku account.
Your work is handing out a shared public/private keypair and encouraging people to set this up as a default identity in SSH? That sounds awful, and it's entirely a problem you created and not even remotely the burden of GitHub or Heroku to care about.
> If I push a repo to Heroku that includes submodules, presumably Heroku then fetches those submodules
You're missing the point. You may use submodules hosted on github with Heroku, but you don't use Heroku to host that repo. You're not going to `git submodule add git@heroku.com:project`. So for the sake of argument, if we pretend that git repo hosts do need to use `git@`, I don't see a single reason why Heroku would.
> And if you're going to suggest that it should only consult users who have access to the repo, for a public project that's everybody, which makes it functionally identical to git@
Now you're confusing two things. Do you want to clone a public module as a subrepo, or allow commit access? Public repos can be cloned without identification. If you want commit access, why would project-level not work?
> Sure it does. IdentityFile is explicitly allowed to be specified multiple times for a single host, and the files will be tried in turn
Again, missing the point. If you don't specify a different host, you'll always be identified and authenticated as the first key that matches, therefore you'll only use a single account. That's why you have to use different hosts.
> And no, your own anecdotes do not constitute proof that providers often have to deal with this.
If you're not going to believe anything I say, I got nothing. Otherwise, 2 things
- I opened an issue and the response was basically "Ooooo that explains some of those tickets". They specifically mentioned issues with vagrant.
- I presented this at a local meetup and someone else had put themselves in this position.
> Your work is handing out a shared public/private keypair and encouraging people to set this up as a default identity in SSH?
No. As I said, it was meant to setup the vagrant box and then not be used. By default vagrant connects using an insecure keypair.
> You may use submodules hosted on github with Heroku, but you don't use Heroku to host that repo.
Ah, I see what you mean. But is that actually true? If you push a repo to Heroku, are you still expecting to host the canonical version of that repo elsewhere, instead of just using Heroku as the canonical version? Because if it's the latter, and you're working with other people, then it's still useful to have a single URL that identifies the repo.
> Do you want to clone a public module as a subrepo, or allow commit access? Public repos can be cloned without identification.
But you're going over SSH, so you have to negotiate the connection before the server knows what action you're taking. So the SSH connection will be the same whether you're pushing or pulling. You can't negotiate different identities for pushing vs pulling, so whatever identity you settle on has to work for both.
> If you don't specify a different host, you'll always be identified and authenticated as the first key that matches, therefore you'll only use a single account. That's why you have to use different hosts.
Ah, I see.
It sounds to me like using username@ is still completely useless regarding your proposed "attack", but does have some small utility for people who have multiple accounts. But I still think the obvious general utility of having a single URL that works for everyone is more important.
As an aside, it looks to me like you could try using the `Match` keyword in your ssh_config and have it run an external command that determines which account you should be using. This could be controlled with an environment var, or maybe it could look at $PWD. If you can come up with some suitable command, then you can use that to control which identity file to use.
> If you're not going to believe anything I say, I got nothing.
I believe your personal, anecdotes, but you can't just make a broad claim about providers with no evidence and expect me to believe that it really is as widespread an issue as you claim.
"It's because the URL is supposed to identify the project, not the user. If the URL included the user's own username, that URL wouldn't work for anyone else."
Couldn't the URL just not include a username, though? Then when git tries to establish an ssh connection, it could try the local username (like ssh does by default), or a username specified somewhere in a config file.
Forgive me ignorance here but what steps should I take to avoid someone from getting my public key off github and then using it to screw with my repos? Was there a major step I missed here when I made these keys?
If you trust your connection to Github and trust that the person in control of the account is the person the account represents, then why not trust that key?
It's public key because it's named such in the context of public key cryptography. But not all public keys should be available to public.
Ideally by default ssh client should use a different key pair for each server('s public key) it connects to. Some people want to hide their identity, for example Tox people chose to be anonymous, what SSH does goes against expectations so it has the ability to betray their choice.
To make it easier. Your public key is something others would place on their servers to grant you access, and you'll need to have your private key to authenticate.
+---------------------------------------------------------------------+
| |
| _o/ Hello! |
| |
| |
| Did you know that ssh sends all your public keys to any server |
| it tries to authenticate to? You can see yours echoed below. |
| |
| We tried to use that to find your GitHub username, but we |
| couldn't :( maybe you don't even have GitHub ssh keys, do you? |
| |
| By the way, did you know that GitHub publishes all users' |
| ssh public keys and Ben (benjojo.co.uk) grabbed them all? |
| |
| That's pretty handy at times :) But not this time :( |
| |
| |
| P.S. This whole thingy is Open Source! (And written in Go!) |
| https://github.com/FiloSottile/whosthere |
| |
| -- @FiloSottile (https://twitter.com/FiloSottile) |
| |
+---------------------------------------------------------------------+
And for those that want to see what a successful key check looks like:
+---------------------------------------------------------------------+
| |
| _o/ Hello Evan Tschuy!
| |
| |
| Did you know that ssh sends all your public keys to any server |
| it tries to authenticate to? |
| |
| That's how we know you are @tschuy on GitHub!
| |
| Ah, maybe what you did't know is that GitHub publishes all users' |
| ssh public keys and Ben (benjojo.co.uk) grabbed them all. |
| |
| That's pretty handy at times :) for example your key is at |
| https://github.com/tschuy.keys
| |
| |
| P.S. This whole thingy is Open Source! (And written in Go!) |
| https://github.com/FiloSottile/whosthere |
| |
| -- @FiloSottile (https://twitter.com/FiloSottile) |
| |
+---------------------------------------------------------------------+
It prints a message and immediately boots you out. By default, Putty will close the window when the connection terminates. Here is the message I got:
$ ssh whoami.filippo.io
The authenticity of host 'whoami.filippo.io (178.32.139.168)' can't be established.
RSA key fingerprint is c8:9a:b0:9d:59:96:24:37:70:4c:ef:eb:31:47:68:40.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'whoami.filippo.io,178.32.139.168' (RSA) to the list of known hosts.
+---------------------------------------------------------------------+
| |
| _o/ Hello Jason Hutchinson!
| |
| |
| Did you know that ssh sends all your public keys to any server |
| it tries to authenticate to? |
| |
| That's how we know you are @zikes on GitHub!
| |
| Ah, maybe what you did't know is that GitHub publishes all users' |
| ssh public keys and Ben (benjojo.co.uk) grabbed them all. |
| |
| That's pretty handy at times :) for example your key is at |
| https://github.com/zikes.keys
| |
| |
| P.S. This whole thingy is Open Source! (And written in Go!) |
| https://github.com/FiloSottile/whosthere |
| |
| -- @FiloSottile (https://twitter.com/FiloSottile) |
| |
+---------------------------------------------------------------------+
Connection to whoami.filippo.io closed.
Strictly speaking, it didn't fail; PuTTY on Windows works a bit differently from command-line ssh on OS X/Linux, and doesn't show you everything. It brings you directly to a "login as:" prompt after throwing up a dialog about missing/unknown keys. What you were supposed to see never made it to the screen.
Interesting. When I tried it at work earlier (Windows 7, latest PuTTY) it closed out the window without showing anything. I just tried it at home (Windows 10, latest PuTTY) and it worked as you said.
Right there in front of me. Now I'm wondering when and why I changed that behavior at home (I'm assuming the "Only on clean exit" setting is the default).
+---------------------------------------------------------------------+
| |
| _o/ Hello! |
| |
| |
| Did you know that ssh sends all your public keys to any server |
| it tries to authenticate to? You can see yours echoed below. |
| |
| We tried to use that to find your GitHub username, but we |
| couldn't :( maybe you don't even have GitHub ssh keys, do you? |
| |
| By the way, did you know that GitHub publishes all users' |
| ssh public keys and Ben (benjojo.co.uk) grabbed them all? |
| |
| That's pretty handy at times :) But not this time :( |
| |
| |
| P.S. This whole thingy is Open Source! (And written in Go!) |
| https://github.com/FiloSottile/whosthere |
| |
| -- @FiloSottile (https://twitter.com/FiloSottile) |
| |
+---------------------------------------------------------------------+
That's a very good thing to keep in mind when reading any complaints on the Internet and using them to gauge sentiment about a thing. Folks who are happy with a thing are far less likely to take the time to write up their experience than those who are unhappy.
It's probably most apt to working when the local username is the same as the username in your SSH keys.
If your local username is something like "johndoe", while your server logins (and keys mapping to them) is "jdoe", it isn't likely to align the one to the other.
If your local and remote usernames tend to be the same, and they are also the same as your Github keys, then it's probably pretty likely to be accurate.
* Your ssh version uses only recent algorithms not supported by Go's x/crypto/ssh
* You actually disabled IdentityKeys
Nothing to do with usernames or heuristics, by the way. All it does is first enumerate your client keys, then let you in, then check a huge GitHub keys database, then ask the GitHub API for your name.
Whenever I push, I login. Apparently this laziness saved my ass this time. Of course, this could be used on any service I ssh into regularly and has a scrappable listing of users, so it's good of you to bring this up.
It also does not work with keys from a smartcard (yubikey NEO). Here is the ssh log:
debug1: Next authentication method: publickey
debug1: Offering RSA public key: cardno:000603010929
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey,keyboard-interactive
debug1: Trying private key: /home/pbonzini/.ssh/id_rsa
debug1: Trying private key: /home/pbonzini/.ssh/id_dsa
debug1: Trying private key: /home/pbonzini/.ssh/id_ecdsa
debug1: Trying private key: /home/pbonzini/.ssh/id_ed25519
debug2: we did not send a packet, disable method
debug1: No more authentication methods to try.
Neat stuff. You could use this to let users identify themselves to services/ssh services via pubkey as their GitHub username - like https://github.com/shazow/ssh-chat - but with users automatically unique and identified by GitHub.
In all seriousity, I would love a similar SSH server that automatically uses keys from GitHub for authentication. Great for setting up a little private git server without fiddling with keys.
Pretty interesting. Although it couldn't find my github ssh keys for some reason. Maybe the database has some stale entries? I imagine it's quite a lot of user data to go through and process.
Does the server get the client's public key before or after the client has identified the server? I suspect it's after - which would imply that this is much less harmful than it looks like, since by then you've already confirmed the identity of the server.
So if my assumption is correct (some quick googling for images of the ssh key exchange suggests it is), then the reason it "works" in this case is because people intentionally say "yes" when presented with the fingerprint, just to see what would happen. If you were ssh-ing to a server that you've used before, there is little to worry about because the ssh client first authenticates the server, and the server presumably needs to know who you are anyway.
It should be safe to say "yes" to any fingerprint from any server you don't trust (as long as you don't send any sensitive information over the connection, or trust information coming from it). The risk is that you accept a fingerprint for a server you do trust, allowing some other server to steal that trust.
You should be using different key pairs on each client machine you log into. You should also be using different key pairs for each host to which you connect (and using ~/.ssh/config to specify which keys are sent to which hosts.)
Not only will this limit correlation as demonstrated here, but also make it much easier to revoke access via keys that may have been compromised.
Though it may be incredibly impractical or theoretically impossible, depending on the key and time of day, there is always a possibility that a public key can be used as an attack vector to guess a private key.
As much as the keys contain public data, I wouldn't consider (but it apparently is) the list of keys with access to my github account public data. Github willingly reveals information about pseudonyms, etc.
This is a data vs metadata thing, the data is public, but who it belongs to, and what one can do with it need not be.
FYI, this happens because SSH automatically presents a public key to the server when trying to authenticate. If the server doesn't know that key, then SSH tries the next one. You can enumerate all of someone's keys this way (like this SSH server does)
If you want to disable this sort of behaviour you can disable SSH from sending keys automatically, and then tell SSH which identity files need to be sent to each host.
In your .ssh/config, something like:
# Ignore SSH keys unless specified in Host subsection
IdentitiesOnly yes
# Send your public key to github only
Host github.com
IdentityFile ~/.ssh/id_rsa
This is also handy if you're security conscious and like to use a different private/public key pair for each host you have an account with!
Exactly! Once I get the keys I just check them against a scraped database of GitHub keys and ask the API for your name.
(And if you have agent forwarding active I show you a big WARNING [0].)
There's an explanation in the README [1] but the actually interesting stuff is in server.go [2]. Finally I mentioned a few reasons it might not work for you below [3].
> (And if you have agent forwarding active I show you a big WARNING [0].)
It amazes me that people enable that for random servers. Seems like SSH should make that harder. Enabling it for a specific server you trust makes sense; enabling it for all servers doesn't. SSH could reject "ForwardAgent" outside a Host block, for instance, and force you to at least write a "Host *" block.
Holy mother of god, can we somehow return to the time when almost nobody used *nix and Microsoft was the one struggling to keep systems of these people secure?
I don't think this time ever existed, I remember some fifteen years ago using google to search for unshadowed /etc/passwd and vulnerable cgi scripts, and there were tons of results.
For those who don't get why this is terrible, imagine if GitHub were compromised and their ssh agent tampered with. When you clone a repo, they could use your forwarded agent to log into your production hosts. That's pretty bad.
I don't fully understand how this would work - the key being "forwarded agent". My (poor) understanding is that in order for compromised github to get to a host I'm connected to they would somehow need to invoke ssh on my host, somehow. The only way that would not be the case is if ssh maintains an in-memory persistent thing that a) maintains connections to foreign hosts, and b) can somehow be signaled from active connections. If that's true, then a) I didn't realize it could do that, and b) it would be quite handy sometimes, although the security implications are rather serious.
The SSH agent maintains your private keys and provides the necessary responses to ssh when it wants to authenticate to a server. If you ssh to a server and forward your SSH agent, that server can then run ssh themselves and impersonate you to a different remote server, and your SSH agent will supply the necessary authentication information.
Or, in short: never use ForwardAgent (or ssh -A) to a server you don't trust.
The remote ssh process asks your host to unencrypt it's traffic? Your process takes an encrypted stream, sends the plaintext, and your keys never leave your machine. That's...incredibly clever, although I can only think of one scenario where it would be necessary (navigating securely through a sequence of ssh sessions where some of the secondary hosts are inaccessible from your originating host. E.g. a kind of "secure trojan horse".
Sometimes I feel just so awed at the ingenuity of people, especially with software and computers.
Safer than dumping all your private keys onto the jump box and using that to validate the final target? Why yes. This way, your local ssh client validates the final target public key, not the jump box.
The whole point of agent forwarding is that you don't have to place your keys on the jump box. With -c for per use confirmation it seems much more secure.
I know it as a "jump host" or "jump box". Regardless, it's still not a good idea to have agent forwarding - what about the boxes you forward to? Do you trust them not to abuse the forwarding trust (Is there a way to limit forwarding trust to just one machine?)
Not exactly. The remote host, which you have forwarded your agent to, tries to log onto your production host using your public key, and when the production host sends it a signing challenge to prove it has the authority of your private key, it can simply ask your ssh agent to do that signing. Once that is complete, you are logged in and the session has a session key that has nothing to do with your pub/private keys. The ssh agent does not do decryption, it just gets the session started.
Another example is if I want to transfer something from server A to server B, without it going through my shitty little pipe, and without storing the private key on either server.
I also use the -c (confirm) flag with ssh-add. I don't forward the agent willy-nilly, but if someone still manages to compromise the agent, I will hopefully know when I'm getting confirmation popups I didn't initiate.
It's been awhile since I set it up, but I believe I've disabled gnome-keyring's agent[1], use the OpenSSH one instead, use ssh-askpass-keyring[2] as the SSH_ASKPASS environment variable to ssh-add to read key passphrases from the keyring (manually invoked via a shell script helper; but only needs to be done once per login session), and GNOME's gnome-ssh-askpass installed as the system default, for key confirmations.
(This is on the Cinnamon desktop, so other GNOME setups could be different.)
There's something I found on hacker news awhile back that can allow you to use ForwardAgent while limiting your identities so that you can forward your ssh agent, but it only forwards the identity you used to connect to that server. It starts up a separate agent for each identity when you invoke it.
Thanks for the tip. I use ForwardAgent for all my servers at work, but I had it defined in a "Host *" block. I've now setup separate blocks for my work domains and have moved ForwardAgent into there alone. Never knew it was a risk until this thread.
Is there a way to set that in bulk so all hosts in your config send identities, but those not specified don't, without putting IdentityFile for every one?
You can create a host block that matches multiple hosts:
IdentitiesOnly yes
Host first second third fourth
IdentitiesOnly no
If you then wanted to have per-host configs you'd have to create more host blocks, but at least this way the added overhead of "IdentitesOnly yes" doesn't grow too fast with the number of hosts involved.
I added IdentitiesOnly to my config recently. Partially for security. But also because an non-Github git service would bail whenever too many incorrect identity files were attempted. I've also had SSH servers bail when trying too many keys/identities.
Yeah, IIRC the error with too many identities is hard to diagnose (something generic like "too many authentication failures"), until you add -v and see all your keys being presented.
Yes, provided that the server accepted the second key the rest would not be sent. However, the server can simply respond that each key is incorrect (regardless of if it is or not), and then get all five keys.
Once SSH has ran out of keys to try, it tries to move on to other authentication methods. The go app he has written then automatically accepts the connection at that point, once it knows it has seen all of your keys.
Double-reading the man page I noticed that IdentitiesOnly makes ssh only send IdentityFile keys, however IdentityFile has a default of "~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ed25519 and ~/.ssh/id_rsa".
The result is that with this configuration you would still send id_rsa to unknown hosts.
You also need to add "PubkeyAuthentication no" to your global stanza, and re-enable it for good hosts.
# Ignore ssh-agent keys
IdentitiesOnly yes
# Disable public key authentication
PubkeyAuthentication no
# Send your public key to github only
Host github.com
PubkeyAuthentication yes
IdentityFile ~/.ssh/id_rsa
Ah, good catch! I don't normally name my keys after the default "id_rsa" so I didn't notice that. You will need that configuration you showed if you have keys that use the default value.
It allows you to do things like have varying passphrase strength on your encrypted keys, depending on how much you care about keeping each one safe; or putting only the private keys you usually need on each device, rather than one/few keys that will get all your systems pwned if it's compromised.
Exactly. Additionally, if I associate a new key pair with each host then I know I can discard + regenerate that key and it only affects that host. Each machine can have their own pairs as well.
If a key is compromised, it only provides access to a single host, not _all_ of them. This allows much more fine-tuned key management and reduces the scope of a key compromise.
Plus, it's not really that much more work. Just name your key after the host it's for, and then add an IdentityFile directive in your SSH config. I never have to worry about it, and get all the benefits.
Didn't work for me, not because I don't have a Github key, but because I use separate keys for everything, and don't have a default key (requires plenty of ~/.ssh/config muckery).
I had been doing this because I'm paranoid, and because I have a tendency to copy keys for my colo boxes to work computers, and my Git keys to the colo boxes. Now I have a new reason -- public keys basically act like a giant supercookie for SSH.
Same here. Here's my ~/.ssh/config for anyone interested in what it looks like:
Host github.com
User toxicFork
IdentityFile ~/.ssh/github-toxicFork
Host bitbucket.org
User toxicFork
IdentityFile ~/.ssh/bitbucket-toxicFork
And my personal security policy:
- Once I want to use a device for development, I create separate key pairs for all of the services I want to use, register it on that server's account config and then add it to my config file by hand ( I should find or write a script to do these automatically :D )
- Once I want to retire a device (or if it gets lost) I just remove the public keys from the services
- NEVER move or copy private keys, I'd rather create a new private key and remove the references for the old public keys instead
Good policies, the mere presence of an id_<ciphername> key in .ssh means you can be identified between multiple ssh servers. I identified this in the OpenSSH source a while ago and posted it on reddit at one point, but few people understood. Glad someone made a practical attack out of it now. IP correlation may seem a more obvious attack, but such an attack could be used to identify for example, someone running a darknet operation or using VPNs for privacy or simply to tie an IP to a name using a public key service like in this example.
It didn't work for me even though I have a github account and ssh key installed from the same machine. Maybe related to the fact I use several keys and keychain to manage keys.
A great reminder that public key identity management is quite the unsolved annoyance. Why should you use the same key everywhere, allowing others to track you? Ideally you would have one key per service.
The host you're connecting to could be able to, force write/destroy your public repos or clone your (and your employer's) private repos given that he knows their paths, eg: github/github. I'd assume that a few companies have a */secrets repo of some sort.
Don't use agent forwarding to any host you don't have exclusive root access to and are 100% sure isn't compromised. Anyone else who is root on a box you SSH to with agent forwarding can authenticate to other servers using your private key while you are connected.
weird idea: server that hosts open source git repos, but won't let you ssh in to clone unless your GitHub account has contributed to an open source project this year.
255 comments
[ 3.2 ms ] story [ 277 ms ] threadYou don't have to phish on HN to get people to connect to an SSH port.
;)
> We tried to use that to find your GitHub username, but we couldn't :( maybe you don't even have GitHub ssh keys, do you?
> By the way, did you know that GitHub publishes all users' ssh public keys and Ben (benjojo.co.uk) grabbed them all?
> That's pretty handy at times :) But not this time :(
Better luck next time, I guess :)
>Better luck next time, I guess :)
Who cares if they publish Public Keys. They're meant to be public, it's one of the few well named things in computer science. They are basically meant to be spewn everywhere.
DOS is the one attack one can not defend against, only attenuate.
Public keys are supposed to be public.
> A simple solution would be to avoid the single user login git@service.com, and use that as identification, for example gmalette@service.com.
Except this completely ignores the reason why services use git@service.com. It's not because they're lazy. It's because the URL is supposed to identify the project, not the user. If the URL included the user's own username, that URL wouldn't work for anyone else, which breaks git-submodules, breaks any kind of config file that specifies repositories (e.g. for use by a CI server), and removes the ability for people to copy&paste a `git clone` command from a README (or blog post or wherever else).
So yes, there is a theoretical annoyance attack here, but nobody really cares because it's never going to happen accidentally, it can't be used against most people, and it's so trivially bypassed nobody's going to bother doing it except as a PoC. The benefits of using git@service.com greatly outweigh the downsides.
The article does mention it. The issue is not fixing the problem, it's actually finding it.
> [...] that URL wouldn't work for anyone else, which breaks git-submodules, breaks any kind of config file that specifies repositories (e.g. for use by a CI server)
It doesn't explain why Heroku uses it. Do you really push different submodules to Heroku?
For Github et. al, that's easily solved by project-level or organization-level identity.
> that URL wouldn't work for anyone else
And using `git@` doesn't work if you use multiple accounts because you'd specify the IdentityFile by host.
> nobody really cares because it's never going to happen accidentally
Except it does. Those service providers often get contacted because this happens BY ACCIDENT.
I've done it to myself by adding my public key to my work account. I couldn't access my personal stuff without changing my SSH config.
A while ago at work, we were using a shared key that was used to setup the initial vagrant config. New hires often added that key to their github or heroku account.
I've heard similar stories elsewhere too.
I don't use Heroku, but, sure, why not? If I push a repo to Heroku that includes submodules, presumably Heroku then fetches those submodules (I'm assuming it supports submodules at all, which seems like an obvious thing to support). Therefore, those submodules must be specified by a URL that works for everyone, not just you.
> For Github et. al, that's easily solved by project-level or organization-level identity.
How does that solve anything? You're no longer identifying the user whose key is supposed to be used, which means this no longer solves your problem. And if you're going to suggest that it should only consult users who have access to the repo, for a public project that's everybody, which makes it functionally identical to git@.
> And using `git@` doesn't work if you use multiple accounts because you'd specify the IdentityFile by host.
Sure it does. IdentityFile is explicitly allowed to be specified multiple times for a single host, and the files will be tried in turn. So you can specify all your keys that way.
> Those service providers often get contacted because this happens BY ACCIDENT.
Someone uploads a private key that doesn't belong to them by accident, that screws up other innocent people? I'm rather skeptical. What's your source on this? And no, your own anecdotes do not constitute proof that providers often have to deal with this.
> A while ago at work, we were using a shared key that was used to setup the initial vagrant config. New hires often added that key to their github or heroku account.
Your work is handing out a shared public/private keypair and encouraging people to set this up as a default identity in SSH? That sounds awful, and it's entirely a problem you created and not even remotely the burden of GitHub or Heroku to care about.
You're missing the point. You may use submodules hosted on github with Heroku, but you don't use Heroku to host that repo. You're not going to `git submodule add git@heroku.com:project`. So for the sake of argument, if we pretend that git repo hosts do need to use `git@`, I don't see a single reason why Heroku would.
> And if you're going to suggest that it should only consult users who have access to the repo, for a public project that's everybody, which makes it functionally identical to git@
Now you're confusing two things. Do you want to clone a public module as a subrepo, or allow commit access? Public repos can be cloned without identification. If you want commit access, why would project-level not work?
> Sure it does. IdentityFile is explicitly allowed to be specified multiple times for a single host, and the files will be tried in turn
Again, missing the point. If you don't specify a different host, you'll always be identified and authenticated as the first key that matches, therefore you'll only use a single account. That's why you have to use different hosts.
> And no, your own anecdotes do not constitute proof that providers often have to deal with this.
If you're not going to believe anything I say, I got nothing. Otherwise, 2 things
- I opened an issue and the response was basically "Ooooo that explains some of those tickets". They specifically mentioned issues with vagrant. - I presented this at a local meetup and someone else had put themselves in this position.
> Your work is handing out a shared public/private keypair and encouraging people to set this up as a default identity in SSH?
No. As I said, it was meant to setup the vagrant box and then not be used. By default vagrant connects using an insecure keypair.
Ah, I see what you mean. But is that actually true? If you push a repo to Heroku, are you still expecting to host the canonical version of that repo elsewhere, instead of just using Heroku as the canonical version? Because if it's the latter, and you're working with other people, then it's still useful to have a single URL that identifies the repo.
> Do you want to clone a public module as a subrepo, or allow commit access? Public repos can be cloned without identification.
But you're going over SSH, so you have to negotiate the connection before the server knows what action you're taking. So the SSH connection will be the same whether you're pushing or pulling. You can't negotiate different identities for pushing vs pulling, so whatever identity you settle on has to work for both.
> If you don't specify a different host, you'll always be identified and authenticated as the first key that matches, therefore you'll only use a single account. That's why you have to use different hosts.
Ah, I see.
It sounds to me like using username@ is still completely useless regarding your proposed "attack", but does have some small utility for people who have multiple accounts. But I still think the obvious general utility of having a single URL that works for everyone is more important.
As an aside, it looks to me like you could try using the `Match` keyword in your ssh_config and have it run an external command that determines which account you should be using. This could be controlled with an environment var, or maybe it could look at $PWD. If you can come up with some suitable command, then you can use that to control which identity file to use.
> If you're not going to believe anything I say, I got nothing.
I believe your personal, anecdotes, but you can't just make a broad claim about providers with no evidence and expect me to believe that it really is as widespread an issue as you claim.
Couldn't the URL just not include a username, though? Then when git tries to establish an ssh connection, it could try the local username (like ssh does by default), or a username specified somewhere in a config file.
If it enables security research it's already a win in my eyes.
Might expose classes of weak keys in the future for example.
[0] https://blog.benjojo.co.uk/post/auditing-github-users-keys
It's public key because it's named such in the context of public key cryptography. But not all public keys should be available to public.
Ideally by default ssh client should use a different key pair for each server('s public key) it connects to. Some people want to hide their identity, for example Tox people chose to be anonymous, what SSH does goes against expectations so it has the ability to betray their choice.
That's what happens to me from OpenWrt
http://i.imgur.com/6G3NxvJ.png
I cleaned out .ssh/knownhosts after connecting.
Connection to whoami.filippo.io closed.Arams-MacBook-Pro:~ acomjean$ emacs .ssh/known_hosts
If your local username is something like "johndoe", while your server logins (and keys mapping to them) is "jdoe", it isn't likely to align the one to the other.
If your local and remote usernames tend to be the same, and they are also the same as your Github keys, then it's probably pretty likely to be accurate.
* You don't have your SSH keys on GitHub
* You don't have your GitHub keys on that laptop
* Your key is not RSA (because I'm LAZY)
* Your ssh version uses only recent algorithms not supported by Go's x/crypto/ssh
* You actually disabled IdentityKeys
Nothing to do with usernames or heuristics, by the way. All it does is first enumerate your client keys, then let you in, then check a huge GitHub keys database, then ask the GitHub API for your name.
https://github.com/FiloSottile/whosthere#how-it-works
Aren't these published by github too?
So, for your login service you scrap github periodically, and only trust things that have been there a month ago already.
(A bit like ssh being vulnerable to MitM attack on the very first connection, but not afterwards.)
So if my assumption is correct (some quick googling for images of the ssh key exchange suggests it is), then the reason it "works" in this case is because people intentionally say "yes" when presented with the fingerprint, just to see what would happen. If you were ssh-ing to a server that you've used before, there is little to worry about because the ssh client first authenticates the server, and the server presumably needs to know who you are anyway.
Nicely presented, Filippo!
IdentitiesOnly yes
to my config file.
I wonder if this means we should be rotating keys periodically? I know most companies require users to rotate their password every X days.
Also, does GitHub have a setting to disable public key publishing?
Not only will this limit correlation as demonstrated here, but also make it much easier to revoke access via keys that may have been compromised.
This is a data vs metadata thing, the data is public, but who it belongs to, and what one can do with it need not be.
If you want to disable this sort of behaviour you can disable SSH from sending keys automatically, and then tell SSH which identity files need to be sent to each host.
In your .ssh/config, something like:
This is also handy if you're security conscious and like to use a different private/public key pair for each host you have an account with!(And if you have agent forwarding active I show you a big WARNING [0].)
There's an explanation in the README [1] but the actually interesting stuff is in server.go [2]. Finally I mentioned a few reasons it might not work for you below [3].
[0] http://git.io/vOVYm
[1] https://github.com/FiloSottile/whosthere
[2] https://github.com/FiloSottile/whosthere/blob/master/src/ssh...
[3] https://news.ycombinator.com/item?id=10005169
Agent forwarding sharing is a big one though. Getting people to stop doing that automatically takes a lot of education. https://wiki.mozilla.org/Security/Guidelines/OpenSSH#SSH_age...
It amazes me that people enable that for random servers. Seems like SSH should make that harder. Enabling it for a specific server you trust makes sense; enabling it for all servers doesn't. SSH could reject "ForwardAgent" outside a Host block, for instance, and force you to at least write a "Host *" block.
EDIT: Check out this search: https://github.com/search?utf8=%E2%9C%93&q=ForwardAgent&type...
Holy mother of god, can we somehow return to the time when almost nobody used *nix and Microsoft was the one struggling to keep systems of these people secure?
Or, in short: never use ForwardAgent (or ssh -A) to a server you don't trust.
Sometimes I feel just so awed at the ingenuity of people, especially with software and computers.
Ex.:
A socket that allows dumping the keys isn't really an improvement. If the box is compromised, agent forwarding can still be abused.
> seems much more secure.
Emphasis on "seems".
Also, I used to add every jump combination into my .ssh/config file, but came across a wonderful trick that makes it unnecessary: https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_J...
(This is on the Cinnamon desktop, so other GNOME setups could be different.)
[1] See https://askubuntu.com/questions/63407/where-are-startup-comm... for how to override in your user dir, or find it in the GUI somewhere. [2] https://launchpad.net/ssh-askpass-keyring is the Ubuntu page
You can find it at: https://github.com/ccontavalli/ssh-ident
[1] http://www.hackinglinuxexposed.com/articles/20040705.html
I almost always log into trusted servers, but it's good to be preemptive ;-)
Very cool, people like keep me hooked to HN. Keep it up!
If you have five keys, and the second is the one that's needed, doesn't that mean that only the first two keys are sent?
Anyway, this is very good to know, and I'm going to take action to make this more secure.
Once SSH has ran out of keys to try, it tries to move on to other authentication methods. The go app he has written then automatically accepts the connection at that point, once it knows it has seen all of your keys.
The result is that with this configuration you would still send id_rsa to unknown hosts.
You also need to add "PubkeyAuthentication no" to your global stanza, and re-enable it for good hosts.
More instructions: https://github.com/FiloSottile/whosthere#how-do-i-stop-itAh well, I don't have any default key anyway.
Or rename the id_* keys to something else. If you're using multiple key pairs will want more descriptive names anyway.
This is a tiny tutorial I wrote ages ago:
http://retrieve.tumblr.com/post/228790418/create-ssh-key-for...
That's an odd definition of "security conscious". This looks more like a key management nightmare.
You're still sending the same default username to every host anyway, so what's the point?
If a key is compromised, it only provides access to a single host, not _all_ of them. This allows much more fine-tuned key management and reduces the scope of a key compromise.
Plus, it's not really that much more work. Just name your key after the host it's for, and then add an IdentityFile directive in your SSH config. I never have to worry about it, and get all the benefits.
I had been doing this because I'm paranoid, and because I have a tendency to copy keys for my colo boxes to work computers, and my Git keys to the colo boxes. Now I have a new reason -- public keys basically act like a giant supercookie for SSH.
- Once I want to use a device for development, I create separate key pairs for all of the services I want to use, register it on that server's account config and then add it to my config file by hand ( I should find or write a script to do these automatically :D )
- Once I want to retire a device (or if it gets lost) I just remove the public keys from the services
- NEVER move or copy private keys, I'd rather create a new private key and remove the references for the old public keys instead
And all of my machines are named "host", with user "user" :)
Edit: I don't really know how do say this short and concise, but you should only do this with servers you trust.
* http://rabexc.org/posts/pitfalls-of-ssh-agents
* http://heipei.github.io/2015/02/26/SSH-Agent-Forwarding-cons...
Yes, it's really stupid to enable AgentForwarding.