go version)?go version go1.10 linux/amd64
Yes
go env)?GOARCH="amd64"
GOBIN=""
GOCACHE="/home/rob/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/rob/go/gopath"
GORACE=""
GOROOT="/usr/lib/go"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
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-build916972665=/tmp/go-build -gno-record-gcc-switches"
I wrote this small sample http listener code:
package main
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World"))
})
http.ListenAndServe("localhost:8080", nil)
}
This, as expected, only listens for loopback connections, and it does not respond to requests coming from outside the machine.
I then tried, from the local host, to perform a request with an arbitrary Host header:
curl localhost:8080 --verbose --header "Host: victim.com"
* Rebuilt URL to: localhost:8080/
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: victim.com
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 21 Feb 2018 10:17:55 GMT
< Content-Length: 11
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
Hello World%
Either the request to fail or the documentation for ListenAndServe or Handler to say that the local listener does not check for the Host header and is thus vulnerable to DNS rebinding attacks.
The request obtaining a response, without checks on the host header, and without any documentation on this issue.
Thank you for reporting this @empijei!
I'll page some of the folks on the net/http and security crews @bradfitz @agl @tombergan @FiloSottile.
Depending on the confirmation and severity of the issue after we evaluate it, perhaps in the future, please report security issues first to [email protected] as detailed at https://golang.org/security, but either way, thank you for reporting it!
Check the documentation for ServeMux
In order to only serve your handle for a specific host, your pattern should read:
http.HandleFunc("example.com/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World"))
})
Then a request for victim.com will return a 404.
Oh, I didn't know that, thanks.
Do you think it should be mentioned somewhere else? Or maybe this issue should be described in the documentation?
I suppose we could add some docs about the Host header somewhere.
Change https://golang.org/cl/115116 mentions this issue: net/http: document that Handlers are resposible for validating Host headers
Most helpful comment
I suppose we could add some docs about the Host header somewhere.