mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-13 15:46:49 +03:00
Sanitize redirect Location header to prevent CRLF injection (#2186)
Route RequestCtx.Redirect Location updates through the canonical response header setter so CR and LF bytes are normalized before serialization. Add regression coverage for query-only and fragment-only redirects containing CRLF, and verify the serialized response cannot emit an injected header line.
This commit is contained in:
@@ -1450,7 +1450,7 @@ func (ctx *RequestCtx) RedirectBytes(uri []byte, statusCode int) {
|
||||
}
|
||||
|
||||
func (ctx *RequestCtx) redirect(uri []byte, statusCode int) {
|
||||
ctx.Response.Header.setNonSpecial(strLocation, uri)
|
||||
ctx.Response.Header.SetCanonical(strLocation, uri)
|
||||
statusCode = getRedirectStatusCode(statusCode)
|
||||
ctx.Response.SetStatusCode(statusCode)
|
||||
}
|
||||
|
||||
@@ -567,12 +567,14 @@ func TestRequestCtxRedirect(t *testing.T) {
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "#aaa", "http://qqq/foo/bar?baz=111#aaa")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "?abc=de&f", "http://qqq/foo/bar?abc=de&f")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "?abc=de&f#sf", "http://qqq/foo/bar?abc=de&f#sf")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "?\r\nInjected: yes", "http://qqq/foo/bar? Injected: yes")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "x.html", "http://qqq/foo/x.html")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "x.html?a=1", "http://qqq/foo/x.html?a=1")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "x.html#aaa=bbb&cc=ddd", "http://qqq/foo/x.html#aaa=bbb&cc=ddd")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "x.html?b=1#aaa=bbb&cc=ddd", "http://qqq/foo/x.html?b=1#aaa=bbb&cc=ddd")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "/x.html", "http://qqq/x.html")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "/x.html#aaa=bbb&cc=ddd", "http://qqq/x.html#aaa=bbb&cc=ddd")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "#\r\nInjected: yes", "http://qqq/foo/bar?baz=111# Injected: yes")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "http://foo.bar/baz", "http://foo.bar/baz")
|
||||
testRequestCtxRedirect(t, "http://qqq/foo/bar?baz=111", "https://foo.bar/baz", "https://foo.bar/baz")
|
||||
testRequestCtxRedirect(t, "https://foo.com/bar?aaa", "//google.com/aaa?bb", "https://google.com/aaa?bb")
|
||||
@@ -595,6 +597,12 @@ func testRequestCtxRedirect(t *testing.T, origURL, redirectURL, expectedURL stri
|
||||
if string(loc) != expectedURL {
|
||||
t.Fatalf("unexpected redirect url %q. Expecting %q. origURL=%q, redirectURL=%q", loc, expectedURL, origURL, redirectURL)
|
||||
}
|
||||
if strings.ContainsAny(redirectURL, "\r\n") {
|
||||
s := ctx.Response.String()
|
||||
if strings.Contains(s, "\r\nInjected: yes\r\n") {
|
||||
t.Fatalf("serialized response contains injected header line: %q", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerResponseServerHeader(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user