golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
122.85k stars 17.52k forks source link

cmd/go: go get -u with GIT_TERMINAL_PROMPT=1 combines separate git username/password prompts, which can lead to password being exposed #38090

Open buriedgod opened 4 years ago

buriedgod commented 4 years ago

What version of Go are you using (go version)?

$ go version go1.14.1 linux/amd64

Does this issue reproduce with the latest release?

Not Tested

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/nibin/.cache/go-build"
GOENV="/home/nibin/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/nibin/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/snap/go/5569"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/snap/go/5569/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/nibin/golang/mod-exp/sample-mods/mysample/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build009035298=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I tried to update go module dependency ( 2 separate go modules residing in 2 repos) ( the dependency(s) resides in a private repo ) using GIT_TERMINAL_PROMPT=1 GOSUMDB=off go get -u

What did you expect to see?

Assume Password Entered is : mypassword

Username for 'https://gitlab.com': myusername
Password for 'https://myusername@gitlab.com':
Username for 'https://gitlab.com': myusername
Password for 'https://myusername@gitlab.com':

What did you see instead?

Assume Password Entered is : mypassword

Username for 'https://gitlab.com': 
Username for 'https://gitlab.com': myusername
Password for 'https://myusername@gitlab.com': 
Password for 'https://mypassword@gitlab.com':
andybons commented 4 years ago

@jayconrod @bcmills @matloob

jayconrod commented 4 years ago

This is happening because the go command runs git commands for multiple repositories concurrently. By default, it sets GIT_TERMINAL_PROMPT=0, but it allows users to override that.

The narrow solution here would be to only run one git command at a time if GIT_TERMINAL_PROMPT=1. That doesn't seem like a great experience though.

@bcmills Should we allow GIT_TERMINAL_PROMPT=1 at all, now that ~/.netrc is supported? Does it cover this case?

bcmills commented 4 years ago

We probably should not allow GIT_TERMINAL_PROMPT.

At one point I started adding explicit serialization of Git terminal operations (first setting to 0, then acquiring a lock and setting to 1 if it is set in the containing environment), but after discussion with Russ we decided that that wasn't a great UX, especially given .netrc and the Git credential cache in general.

jayconrod commented 4 years ago

+1 to disallowing GIT_TERMINAL_PROMPT. Let's make sure .netrc and other procedures for accessing private repos are better documented first though. I suspect in most cases, people are only using one private repo and won't run into this issue.

RubenGarcia commented 3 years ago

There needs to be a way to serialize the request for passwords / passphrases. Otherwise people who don't want to write their passwords in plain text cannot even use the old workaround of GIT_TERMINAL_PROMPT=1 to be prompted for the passwords and makes go run and go get no longer usable.

bcmills commented 3 years ago

@RubenGarcia, there are other, cleaner ways to pass credentials to git without storing them on disk. (See, for example, git-credential-cache.)

bwmarrin commented 2 years ago

What would be the way that a user can go get from private repo and avoid this with minimal fuss? I run into this issue frequently and it is pretty frustrating. I'm often on different computers so saving my password on each of them doesn't seem ideal. With the git cache, wouldn't I first need to git clone something to get my password in the cache? It seems kind of silly to git clone a repo just to get my password saved and turn around and use go get to pull it into whatever project I'm working on.

Whatever the method is, I need to be able to explain it to my co-workers so they can avoid the issue too and it should be something simple. Cloning or downloading code should be really simple. There's plenty of other aspects of work and development that's already complicated. Just getting code on your computer should not be one of them. The need for GOPRIVATE and GIT_TERMINAL_PROMPT is already far more complication than it really should have :(

I think the very basic old fashion magic of being able to type in your username and password should work. If that means when using GIT_TERMINAL_PROMPT=1 that go only calls git commands sequentially then that's a far better trade off (to me) then making it not work at all and not allowing someone to just simply type their password in.

I don't run into this as often at my work computer but when I'm on a different system it pops up - like today there was an issue and I needed to try and look at something quickly from home and when I tried to go get a package I got 3 user prompts piled on top of each other and it's pretty much impossible to figure out rather I should be typing a username or password or some magic of both at the same time. :(

bcmills commented 2 years ago

@bwmarrin, one option is to always fetch using HTTPS, with a personal access token stored in a .netrc file.

Another option is to fetch the private repo using SSH, and to use the ControlPath option to set up the connection outside of cmd/go itself; see https://github.com/golang/go/issues/49515#issuecomment-969247066 for some options that seem to work for that. (If you run into trouble with those, please let me know on that issue.)

bwmarrin commented 2 years ago

Thanks for the options @bcmills - I do appreciate the suggestions. These suggestions and the other's I've read in this issue and elsewhere all seem like "work arounds" and that's fine as it helps solve the issue for right now but I don't think they're very good solutions.

Option 1 isn't terrible, I suppose - but it's not very ideal when working on multiple computers and having to leave your auth in a file on all of them. I'm sure there are plenty of cases where leaving your auth info on systems just isn't very viable. Option 2 seems wildly complicated.

I'll re-iterate that I believe downloading a repo should be incredibly easy and in these cases of private repos and/or self hosted repos that isn't the case and I feel like that's a short coming of the Go toolset :(. I still think having a fall back option of being able to simply type your password should exist and work.