{"thread":{"id":"55005","subject":"False negative authentication with multiple accounts on a SSH-GIT server","startedAt":"2021-01-19T06:24:14Z","lastAt":"2021-01-20T19:12:37Z","messageCount":6,"participants":["Harley Paterson","M. Buecher","brian m. carlson","Ævar Arnfjörð Bjarmason","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"414654","messageId":"DB8P189MB10460B9A3CA31ADF5C05A39FF9A30@DB8P189MB1046.EURP189.PROD.OUTLOOK.COM","threadId":"55005","inReplyTo":null,"subject":"False negative authentication with multiple accounts on a SSH-GIT server","fromName":"Harley Paterson","fromEmail":"harley.paterson@hotmail.co.nz","sentAt":"2021-01-19T06:17:21Z","receivedAt":"2021-01-19T06:24:14Z","isPatch":false,"sender":{"key":"harley.paterson@hotmail.co.nz","avatar":null},"body":"Hello,\n\nI've noticed an edge case in Git when a user has two Git accounts on a single server - as might be common for a personal account and a work account on a Git forge (Github, GitLab, Bitbucket...)\n\nWhen attempting SSH login, `ssh` and Git will eagerly connect with the first matching key. This may or may not be the key right key for the repository the user needs. As a result, Git clones, pulls, and pushes will fail with the `Repository not found` if the wrong key is tried first.\n\nFor example, the user `alice` has two accounts on the host `git-server.com`. `alice`'s accounts are `alice-work`, and `alice-personal`. `alice-work` has access to the `foo` repository, and `alice-personal` has access to the `bar` repository.\n\n`alice` attempts to clone `foo` with both her `alice-work` and `alice-personal` keys in her SSH Agent. SSH Agent does not define which key it will attempt first, so SSH may connect successfully to `git-server.com` with her `alice-personal` keys, which do not have access to the `foo` repository.\n\nI'd be interested in your opinions for fixes to this. I am willing to make a patch, although my knowledge of the Git codebase isn't perfect.\n\n- Should Git servers provide distinctly different error messages for `access denied`, and `repository does not exist`? Currently the server immediately closes the connection in this case, so `transport.c:handshake()` with fail when attempting to `discover_version()` because the reader hits the EOF. Perhaps the server could send a hypothetical access denied packet here, and a more appropriate error generated? \n\nCan anyone point me to where in the Git codebase the daemon receives and responds to these requests? I haven't found it yet, if I wanted to patch this.\n\n- Should Git provide a `-i` option to allow the user to choose an SSH key, which could be added to the SSH subprocess's command line?\n\n- Should Git attempt to iterate over all keys in the SSH Agent when the connection is setup, testing the connection to check if each connected key has access to the target repository, before giving up and reporting an error? This may be difficult looking at the current behavior of `ssh` and `ssh-agent`. `ssh-add -l` no longer lists paths to files (which could be plugged into `ssh -i`), just the key signature. Does anyone know of any SSH/SSH-Agent tricks which might help with this?\n\nAll the best,\n\n\n\nH Paterson.\n"},{"id":"414698","messageId":"ddf34d963a57971c13d12d8f0c04a0fc@mailbox.org","threadId":"55005","inReplyTo":"DB8P189MB10460B9A3CA31ADF5C05A39FF9A30@DB8P189MB1046.EURP189.PROD.OUTLOOK.COM","subject":"Re: False negative authentication with multiple accounts on a SSH-GIT server","fromName":"M. Buecher","fromEmail":"maddes+git@maddes.net","sentAt":"2021-01-19T18:22:14Z","receivedAt":"2021-01-19T18:30:14Z","isPatch":false,"sender":{"key":"maddes+git@maddes.net","avatar":null},"body":"Hi there,\n\nyou can use GIT_SSH_COMMAND or config 'core.sshCommand'.\nFor more flexibility use wrappers like ssh-ident.\n\nRecommended read: https://superuser.com/a/1616186/557798\n\nHope this helps\nKind regards\nMaddes\n\n\nOn 2021-01-19 07:17, Harley Paterson wrote:\n> Hello,\n> \n> I've noticed an edge case in Git when a user has two Git accounts on a\n> single server - as might be common for a personal account and a work\n> account on a Git forge (Github, GitLab, Bitbucket...)\n> \n> When attempting SSH login, `ssh` and Git will eagerly connect with the\n> first matching key. This may or may not be the key right key for the\n> repository the user needs. As a result, Git clones, pulls, and pushes\n> will fail with the `Repository not found` if the wrong key is tried\n> first.\n> \n> For example, the user `alice` has two accounts on the host\n> `git-server.com`. `alice`'s accounts are `alice-work`, and\n> `alice-personal`. `alice-work` has access to the `foo` repository, and\n> `alice-personal` has access to the `bar` repository.\n> \n> `alice` attempts to clone `foo` with both her `alice-work` and\n> `alice-personal` keys in her SSH Agent. SSH Agent does not define\n> which key it will attempt first, so SSH may connect successfully to\n> `git-server.com` with her `alice-personal` keys, which do not have\n> access to the `foo` repository.\n> \n> I'd be interested in your opinions for fixes to this. I am willing to\n> make a patch, although my knowledge of the Git codebase isn't perfect.\n> \n> - Should Git servers provide distinctly different error messages for\n> `access denied`, and `repository does not exist`? Currently the server\n> immediately closes the connection in this case, so\n> `transport.c:handshake()` with fail when attempting to\n> `discover_version()` because the reader hits the EOF. Perhaps the\n> server could send a hypothetical access denied packet here, and a more\n> appropriate error generated?\n> \n> Can anyone point me to where in the Git codebase the daemon receives\n> and responds to these requests? I haven't found it yet, if I wanted to\n> patch this.\n> \n> - Should Git provide a `-i` option to allow the user to choose an SSH\n> key, which could be added to the SSH subprocess's command line?\n> \n> - Should Git attempt to iterate over all keys in the SSH Agent when\n> the connection is setup, testing the connection to check if each\n> connected key has access to the target repository, before giving up\n> and reporting an error? This may be difficult looking at the current\n> behavior of `ssh` and `ssh-agent`. `ssh-add -l` no longer lists paths\n> to files (which could be plugged into `ssh -i`), just the key\n> signature. Does anyone know of any SSH/SSH-Agent tricks which might\n> help with this?\n> \n> All the best,\n> \n> \n> \n> H Paterson.\n"},{"id":"414747","messageId":"YAdnJabiJlu9Qlli@camp.crustytoothpaste.net","threadId":"55005","inReplyTo":"DB8P189MB10460B9A3CA31ADF5C05A39FF9A30@DB8P189MB1046.EURP189.PROD.OUTLOOK.COM","subject":"Re: False negative authentication with multiple accounts on a SSH-GIT server","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-01-19T23:11:33Z","receivedAt":"2021-01-19T23:15:00Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2021-01-19 at 06:17:21, Harley Paterson wrote:\n> Hello,\n> \n> I've noticed an edge case in Git when a user has two Git accounts on a\n> single server - as might be common for a personal account and a work\n> account on a Git forge (Github, GitLab, Bitbucket...)\n> \n> When attempting SSH login, `ssh` and Git will eagerly connect with the\n> first matching key. This may or may not be the key right key for the\n> repository the user needs. As a result, Git clones, pulls, and pushes\n> will fail with the `Repository not found` if the wrong key is tried\n> first.\n> \n> For example, the user `alice` has two accounts on the host\n> `git-server.com`. `alice`'s accounts are `alice-work`, and\n> `alice-personal`. `alice-work` has access to the `foo` repository, and\n> `alice-personal` has access to the `bar` repository.\n\nYes, this is because SSH authentication happens before any command is\nrun.  The server never knows what resource is being requested until the\nuser is already authenticated.\n\n> `alice` attempts to clone `foo` with both her `alice-work` and\n> `alice-personal` keys in her SSH Agent. SSH Agent does not define\n> which key it will attempt first, so SSH may connect successfully to\n> `git-server.com` with her `alice-personal` keys, which do not have\n> access to the `foo` repository.\n> \n> I'd be interested in your opinions for fixes to this. I am willing to\n> make a patch, although my knowledge of the Git codebase isn't perfect.\n\nWe've documented how to deal with situation properly in the FAQ, which\nyou can see at gitfaq(7) or\nhttps://git-scm.com/docs/gitfaq#Documentation/gitfaq.txt-HowdoIusemultipleaccountswiththesamehostingproviderusingSSH\n\nIs there some reason that this doesn't work for you?\n\n> - Should Git servers provide distinctly different error messages for\n>   `access denied`, and `repository does not exist`? Currently the\n>   server immediately closes the connection in this case, so\n>   `transport.c:handshake()` with fail when attempting to\n>   `discover_version()` because the reader hits the EOF. Perhaps the\n>   server could send a hypothetical access denied packet here, and a\n>   more appropriate error generated?\n\nUnfortunately, this leaks whether a repository exists.  If Company XYZ\nhas a repository for each of its clients, it then becomes easy to see if\nCompany XYZ is doing work for a particular client by trying to see if a\nrepository exists.  This would be bad and a huge violation of privacy,\nso nobody is likely do to that.  I can tell you as one of the staff who\nmaintains the GitHub Git service, we're not likely to change the\nbehavior, and I suspect nobody else is, either.\n\n> Can anyone point me to where in the Git codebase the daemon receives\n> and responds to these requests? I haven't found it yet, if I wanted to\n> patch this.\n> \n> - Should Git provide a `-i` option to allow the user to choose an SSH\n>   key, which could be added to the SSH subprocess's command line?\n\nYou can use GIT_SSH_COMMAND or `core.sshcommand` to set this.  We don't\nprovide such an option because the user is not necessarily using\nOpenSSH and different SSH programs provide this feature differently.\n\n> - Should Git attempt to iterate over all keys in the SSH Agent when\n>   the connection is setup, testing the connection to check if each\n>   connected key has access to the target repository, before giving up\n>   and reporting an error? This may be difficult looking at the current\n>   behavior of `ssh` and `ssh-agent`. `ssh-add -l` no longer lists\n>   paths to files (which could be plugged into `ssh -i`), just the key\n>   signature. Does anyone know of any SSH/SSH-Agent tricks which might\n>   help with this?\n\nFor historical reasons, we retry SSH connections in Git LFS and users\nfrequently complain about being prompted for their password multiple\ntimes before giving up, so I suspect this would not be a good experience\nfor the user.  Users may also have multiple keys and have configured\ntheir agent to prompt them for a passphrase before using the key, and\nI'm pretty sure those users will complain very loudly if we do this.\n-- \nbrian m. carlson (he/him or they/them)\nHouston, Texas, US\n"},{"id":"414790","messageId":"87im7r93u7.fsf@evledraar.gmail.com","threadId":"55005","inReplyTo":"YAdnJabiJlu9Qlli@camp.crustytoothpaste.net","subject":"Re: False negative authentication with multiple accounts on a SSH-GIT server","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-01-20T12:42:56Z","receivedAt":"2021-01-20T13:00:37Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Jan 20 2021, brian m. carlson wrote:\n\n> On 2021-01-19 at 06:17:21, Harley Paterson wrote:\n>> Hello,\n>> \n>> I've noticed an edge case in Git when a user has two Git accounts on a\n>> single server - as might be common for a personal account and a work\n>> account on a Git forge (Github, GitLab, Bitbucket...)\n>> \n>> When attempting SSH login, `ssh` and Git will eagerly connect with the\n>> first matching key. This may or may not be the key right key for the\n>> repository the user needs. As a result, Git clones, pulls, and pushes\n>> will fail with the `Repository not found` if the wrong key is tried\n>> first.\n>> \n>> For example, the user `alice` has two accounts on the host\n>> `git-server.com`. `alice`'s accounts are `alice-work`, and\n>> `alice-personal`. `alice-work` has access to the `foo` repository, and\n>> `alice-personal` has access to the `bar` repository.\n>\n> Yes, this is because SSH authentication happens before any command is\n> run.  The server never knows what resource is being requested until the\n> user is already authenticated.\n>\n>> `alice` attempts to clone `foo` with both her `alice-work` and\n>> `alice-personal` keys in her SSH Agent. SSH Agent does not define\n>> which key it will attempt first, so SSH may connect successfully to\n>> `git-server.com` with her `alice-personal` keys, which do not have\n>> access to the `foo` repository.\n>> \n>> I'd be interested in your opinions for fixes to this. I am willing to\n>> make a patch, although my knowledge of the Git codebase isn't perfect.\n>\n> We've documented how to deal with situation properly in the FAQ, which\n> you can see at gitfaq(7) or\n> https://git-scm.com/docs/gitfaq#Documentation/gitfaq.txt-HowdoIusemultipleaccountswiththesamehostingproviderusingSSH\n>\n> Is there some reason that this doesn't work for you?\n>\n>> - Should Git servers provide distinctly different error messages for\n>>   `access denied`, and `repository does not exist`? Currently the\n>>   server immediately closes the connection in this case, so\n>>   `transport.c:handshake()` with fail when attempting to\n>>   `discover_version()` because the reader hits the EOF. Perhaps the\n>>   server could send a hypothetical access denied packet here, and a\n>>   more appropriate error generated?\n>\n> Unfortunately, this leaks whether a repository exists.  If Company XYZ\n> has a repository for each of its clients, it then becomes easy to see if\n> Company XYZ is doing work for a particular client by trying to see if a\n> repository exists.\n\nI wonder how many hosting providers are confident that the code involved\nin this isn't vulnerable to a timing attack.\n\n> This would be bad and a huge violation of privacy, so nobody is likely\n> do to that.  I can tell you as one of the staff who maintains the\n> GitHub Git service, we're not likely to change the behavior, and I\n> suspect nobody else is, either.\n\nLet's be clear, it's a violation of privacy in the case that involves a\nprivate repo.\n\nBut the fact that when you e.g. clone git@github.com:git/git.git with no\nvalid key and get a \"Permission denied\" is just an emergent effect of\nhow people string together openssh & their own auth solutions in the\nwild.\n\nYou can just as well let the dialog proceed down to a shell without a\nvalid key or password, and then check that the user wants to run \"git\nupload-pack git/git.git\", and then decide \"sure, it's a public repo\" and\nproceed.\n\nIndeed that's what e.g. GitHub does when you make up a username &\npassword to clone a public repo over https.\n\n    # Under OpenSSH, See https://tools.ietf.org/html/rfc4252#section-5.2\n    Match User git\n        PermitEmptyPasswords yes\n        AuthenticationMethods none\n\nWhy would a site like GitHub treat ssh differently than https here? I\nthink it just comes down to openssh's support for use-case being a bit\nof a pain to configure.\n\nI don't know of a way to do that *and* pass down to e.g. a login shell\nwrapper script if/how the user was authenticated.\n\nHrm, maybe I take that back. I suppose you can make the default shell\nfor the \"git\" user \"git-shell-public\" and set the rw login shell to\n\"git-shell-private\" via an Authorized{Keys,Principals}Command\". But I\nhaven't tested it.\n\nAnyway, just saying that there's bad error messages for good reasons,\nand bad error messages for lazyness/not wanting to deal with the edge\ncase.\n\nWhat Harley Paterson is complaining about is sometimes in the \"good\nreasons\" bucket, but sometimes just server operator lazyness, or not\ncaring about this marginal edge case enough to provide a better error\nmessage.\n"},{"id":"414795","messageId":"YAg/wV05JYbzOdck@coredump.intra.peff.net","threadId":"55005","inReplyTo":"87im7r93u7.fsf@evledraar.gmail.com","subject":"Re: False negative authentication with multiple accounts on a SSH-GIT server","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-01-20T14:35:45Z","receivedAt":"2021-01-20T14:38:18Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 20, 2021 at 01:42:56PM +0100, Ævar Arnfjörð Bjarmason wrote:\n\n> > Unfortunately, this leaks whether a repository exists.  If Company XYZ\n> > has a repository for each of its clients, it then becomes easy to see if\n> > Company XYZ is doing work for a particular client by trying to see if a\n> > repository exists.\n> \n> I wonder how many hosting providers are confident that the code involved\n> in this isn't vulnerable to a timing attack.\n\nI would say \"not very certain\" in the case of GitHub. I don't recall any\nanalysis of the timing ever having happened.\n\n> Why would a site like GitHub treat ssh differently than https here? I\n> think it just comes down to openssh's support for use-case being a bit\n> of a pain to configure.\n\nGitHub doesn't use openssh at all; ssh sessions are terminated at a\ncustom load-balancing/proxy layer daemon.\n\nI agree that servers in general probably could accept this notion of \"no\nvalid user\" for ssh sessions. I just think it's something that nobody\nhas asked for. I.e., if you are not planning to be an authenticated\nuser, then why use ssh in the first place? Certainly you could ask \"why\nnot\", but AFAIK this is the first time it has come up.\n\nThere is one protocol issue I'm not sure of, though. My understanding of\nssh auth is that the client offers keys in sequence, and the server says\n\"yes\" or \"no\" on each. We'd want to continue saying \"no\" on keys that we\ndon't know about, so the client may keep trying other keys to which we\nmight say \"yes\". But after having seen all of the keys, what then?\n\nWe would want the server to say \"OK, even though we don't like any of\nyour keys, let's start a session anyway\". Is that possible within the\nprotocol? I think having the server say \"OK, now try password auth\" is\nnot a good idea. If the client asks for a dummy password, that is likely\nto be either confusing, or disrupt sessions without a human present.\n\nBut I don't know the ssh protocol very well, so perhaps my understanding\nof what is possible totally wrong. https has this much easier because\nunauthenticated requests are totally normal, and the server sees the\nauth along with the whole request at the same time.\n\n-Peff\n"},{"id":"414839","messageId":"DB8P189MB10465B7C7C89FDCD8F8C6155F9A20@DB8P189MB1046.EURP189.PROD.OUTLOOK.COM","threadId":"55005","inReplyTo":"YAg/wV05JYbzOdck@coredump.intra.peff.net","subject":"Re: False negative authentication with multiple accounts on a SSH-GIT server","fromName":"Harley Paterson","fromEmail":"harley.paterson@hotmail.co.nz","sentAt":"2021-01-20T19:11:21Z","receivedAt":"2021-01-20T19:12:37Z","isPatch":false,"sender":{"key":"harley.paterson@hotmail.co.nz","avatar":null},"body":"Repost: Accedentialy forgot to CC this to the mailing list.\n\n>> Unfortunately, this leaks whether a repository exists.  If Company XYZ\n>> has a repository for each of its clients, it then becomes easy to see if\n>> Company XYZ is doing work for a particular client by trying to see if a\n>> repository exists.\n> \n> I wonder how many hosting providers are confident that the code involved\n> in this isn't vulnerable to a timing attack.\n>\n> I would say \"not very certain\" in the case of GitHub. I don't recall any\n> analysis of the timing ever having happened.\n\n\n\nI have to agree with this... It's certainly a risk, but if an attacker has enough\ninformation to guess the repository names/URLs without triggering a rate\nlimiter, they already have a pretty good idea who Company XYZ is likely working\nfor, and what on.\n\nHP.\n\n"}]}