go net/http: readRequest无法处理以空格字符结尾的URI

bq8i3lrv  于 6个月前  发布在  Go
关注(0)|答案(8)|浏览(52)

你正在使用的Go版本是什么( go version )?

$ go version
go version go1.20.2 windows/amd64

这个问题在最新版本中是否重现?

是的。

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\colin\AppData\Local\go-build
set GOENV=C:\Users\colin\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\colin\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\colin\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.20.2
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=J:\Data\Projects\fpProxy\go.mod
set GOWORK=J:\Data\Projects\fpProxy\go.work
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=C:\Users\colin\AppData\Local\Temp\go-build4117129570=/tmp/go-build -gno-record-gcc-switches

你做了什么?

我正在处理一些非常旧的软件,在某些情况下,这些软件会在发送HTTP请求时不去除Request URI中的空白字符。在我们将代理更改为基于Go之后,这些请求无法在应用程序和文件服务器之间被代理接收。
当在应用程序和Go代理服务器之间放置Python或Fiddler代理时,这些请求会突然开始正常工作。我能想到的唯一想法是,它们在通过时对请求进行清理。
我进行了深入的研究,发现在读取请求时, parseRequestLine 的工作假设是请求行中的每个元素都由单个空格字符分隔,如RFC中所定义的那样。当它拆分时,HTTP协议会在其前面多出一个空格。这意味着它会因为格式错误的协议而报错。我知道这种行为并不是RFC严格支持的,但我希望看到它反映出其他软件是如何处理的。
测试这个的最简单的方法是向一个Go HTTP服务器发送 GET /test HTTP/1.0GET /test HTTP/1.0 等变体,后者将返回400 Bad Request错误。
为了演示显示带有空格前缀的协议来自哪里,我复制了当前的 parseRequestLine ,然后将协议输入到 ParseHTTPVersion
https://go.dev/play/p/8F2Q9A5Fhx1

你期望看到什么?

'GET', 'http://www.nabiscoworld.com/shock/nbgrm.dcr', 'HTTP/1.0'

你看到了什么?

'GET', 'http://www.nabiscoworld.com/shock/nbgrm.dcr', ' HTTP/1.0'
Malformed proto
0dxa2lsx

0dxa2lsx2#

解:理想情况下,如果有这样的功能就更好了,可以让他们通过但被转义。

mctunoxg

mctunoxg3#

我知道这种行为并不是RFC严格支持的,但我希望看到它反映出其他软件是如何处理的。
通常情况下,Go语言的net/http会尽量遵循RFCs,除非这种偏差被广泛使用。你能举一些广泛使用的客户端的例子,这些客户端需要这种行为吗?也许能提供更多关于为什么在这些客户端中无法修复它的细节?

wfsdck30

wfsdck304#

这是一个棘手的问题——它并不常用,过去15+年里几乎所有的客户端都不应该这样做,但我们发现一些Adobe Shockwave游戏(大约20-25年前的游戏)中存在错误的使用。
这种行为在其他我尝试过的软件中也有体现——Fiddler、Python、Apache等都处理得很好(事实上,http://go.dev/网站本身认为它是有效的)。我一直很难找到关于为什么它们一开始就支持它的文档,我能找到的唯一资料是1998年URI Generic Syntax RFC中的“语法符号和通用元素”部分,但当2005年的当前RFC出现时,它已经被删除了。
<first>/<second>;<third>?<fourth>
组件名称用尖括号括起来,尖括号外的任何字符都是字面分隔符。应忽略空白。这些描述是非正式的,不定义语法要求。
显然,考虑到我们的使用场景,支持这个功能是值得考虑的,但我也理解你为什么不选择这样做。

hjzp0vay

hjzp0vay5#

Just to add some more samples of it working Using OpenSSL to test, go.dev worked with any number of spaces

All valid (Including spaces AFTER HTTP/1.1)
GET go.dev  HTTP/1.1
GET go.dev    HTTP/1.1
GET        go.dev      HTTP/1.1
GET   go.dev/play/       HTTP/1.1   
GET   https://www.google.com/imghp?hl=en&ogbl       HTTP/1.1
GET        https://learn.microsoft.com/en-us/    HTTP/1.1   
GET        https://httpd.apache.org/    HTTP/1.1   

Invalid (Returns 400)
  GET go.dev HTTP/1.1
GET go.dev/play / HTTP/1.1
GET go.dev/pl ay/ HTTP/1.1

I tried to find other examples of nginx and apache, but I couldn't get any request to work openssl with nginx.org or facebook.com, everything was rejected, I am sure I am doing something wrong.
All sites rejected anything starting with a space, but every site I tried that I could get to work normally worked with multiple spaces between Method and URI and URI and Protocol and Protocol to end.

9ceoxa92

9ceoxa926#

我们使用Golang来解析网络安全中的原始http请求,有一个简单的SQL注入示例,无法通过http.ReadRequest解析。

$ curl -vv "http://10.1.1.2:8010/?id=1 or 1=2"
*   Trying 10.1.1.2:8010...
* TCP_NODELAY set
* Connected to 10.1.1.2 (10.1.1.2) port 8010 (#0)
> GET /?id=1 or 1=2 HTTP/1.1
> Host: 10.1.1.2:8010
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Test-Server
< Date: Tue, 02 Jan 2024 10:16:52 GMT
< Content-Length: 0
<

当然,这不是一个通用的http请求,但我们希望用Go做更多的事情😁

j7dteeu8

j7dteeu87#

看起来我们应该拒绝让解析器变得更宽松。

k5ifujac

k5ifujac8#

看起来我们应该拒绝让解析器变得过于宽松。我的意思是,我们需要更宽松的解析器来使Golang能够解析这些非一般请求。😂
我们想要从http查询中获取键值对 "id" = "1" 或 "1=2"。

相关问题