Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http: request with a + in Content-Length is considered valid #39017

Open
juliens opened this issue May 12, 2020 · 3 comments
Open

net/http: request with a + in Content-Length is considered valid #39017

juliens opened this issue May 12, 2020 · 3 comments
Assignees
Milestone

Comments

@juliens
Copy link
Contributor

@juliens juliens commented May 12, 2020

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

$ go version
go version go1.14.2 linux/amd64

Does this issue reproduce with the latest release?

Yes

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

go env Output
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/juliens/.cache/go-build"
GOENV="/home/juliens/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GOOS="linux"
GOPATH="/home/juliens/dev/go"
GOPRIVATE=""
GOPROXY="direct"
GOROOT="/home/juliens/go-current"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/juliens/go-current/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
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-build262375258=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I launch a server using

http.ListenAndServe(":8080", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
    fmt.Println(req.ContentLength)
}))

and after that, I make a call with a Content-Length: +3

echo -ne "POST / HTTP/1.1\r\nContent-Length: +3\r\nHost: 127.0.0.1\r\n\r\naaa\r\n" | nc 127.0.0.1 8083

What did you expect to see?

A bad request ( because of the RFC https://tools.ietf.org/html/rfc2616#section-14.13 )

What did you see instead?

A valid request, the Content-Length is parsed as just 3

More

For what I saw, it's because the Content-Length is parsed by using strconv.ParseInt and so +3 is valid and becomes 3

@tpaschalis
Copy link
Contributor

@tpaschalis tpaschalis commented May 21, 2020

I'd like to take a stab if there's no objection from the Go team!

For my first attempt, I simply used strconv.ParseUint (which disallows the prefixed sign), to replace the strconv.ParseInt calls (that allow it), and then cast back to int64. I'm using ParseUint(cl, 10, 63) to leave that extra sign bit, so it's safe to convert back to an int64.

From some manual testing, this seems to do the trick. I've added some unit test that reference this issue for posterity and have opened a CL.

With that change, I get

func main() {
    http.ListenAndServe(":8080", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        fmt.Println(req.ContentLength)
    }))
## Before
$ go run main.go
$ echo -ne "POST / HTTP/1.1\r\nContent-Length: 3\r\nHost: 127.0.0.1\r\n\r\naaa\r\n" | nc 127.0.0.1 8080
HTTP/1.1 200 OK
...

$ echo -ne "POST / HTTP/1.1\r\nContent-Length: +3\r\nHost: 127.0.0.1\r\n\r\naaa\r\n" | nc 127.0.0.1 8080
HTTP/1.1 200 OK
...

## After
$ $GODIR/bin/go run main.go
$ echo -ne "POST / HTTP/1.1\r\nContent-Length: 3\r\nHost: 127.0.0.1\r\n\r\naaa\r\n" | nc 127.0.0.1 8080
HTTP/1.1 200 OK
...

$ echo -ne "POST / HTTP/1.1\r\nContent-Length: +3\r\nHost: 127.0.0.1\r\n\r\naaa\r\n" | nc 127.0.0.1 8080
HTTP/1.1 400 Bad Request
...
@gopherbot
Copy link

@gopherbot gopherbot commented May 21, 2020

Change https://golang.org/cl/234817 mentions this issue: net/http: Disallow plus symbol in Content-Length

@odeke-em
Copy link
Member

@odeke-em odeke-em commented May 23, 2020

Thank you for the report @juliens! Thank you for working on the fix @tpaschalis, awesome!
I've added some suggestions to your CL, please take a look. Our HTTP/2 stack purposefully skips checking for errors from strconv.ParseInt, because such errors don't necessarily affect our framing. Unfortunately this increases the surface area for what could change be broken within this release that we are already in.

@bradfitz would it be pragmatic for us to firstly accept only the fix for HTTP/1.1 for Go1.15? For Go1.16 make the follow-on update in x/net/http2 and subsequently to net/http/h2_bundle.go? We ignore the errors anyways in HTTP/2 so the change could perhaps survive one more release.

gopherbot pushed a commit that referenced this issue May 31, 2020
Enforces section 14.13 of RFC 2616 so that Content-Length header
values with a sign such as "+5" will be rejected.

Updates #39017

Change-Id: Icce9f00d03c8475fe704b33f9bed9089ff8802f0
Reviewed-on: https://go-review.googlesource.com/c/go/+/234817
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.