Problem
This package (v1.2.1 and possibly earlier versions) suffers from a similar (though less severe) form of rs/cors#170. Processing a preflight request with a maliciously long Access-Control-Request-Headers header indeed requires a relatively long time and causes a lot of undue heap allocations. For example, processing a single malicious preflight request whose ACRH header comprises 1MiB's worth of commas takes about 5ms and allocates about 17 MiB:
var testHandler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, _ = io.WriteString(w, "bar")
})
func BenchmarkPreflight(b *testing.B) {
req := httptest.NewRequest(http.MethodOptions, "https://example.org/admin", nil)
req.Header.Add("Origin", "https://example.com")
req.Header.Add("Access-Control-Request-Method", http.MethodGet)
req.Header.Add("Access-Control-Request-Headers", "Authorization")
handler := Handler(Options{})(testHandler)
b.ReportAllocs()
b.ResetTimer()
for range b.N {
res := httptest.NewRecorder()
handler.ServeHTTP(res, req)
}
}
func BenchmarkPreflightAdversarialACRH(b *testing.B) {
req := httptest.NewRequest(http.MethodOptions, "https://example.org/admin", nil)
req.Header.Add("Origin", "https://example.com")
req.Header.Add("Access-Control-Request-Method", http.MethodGet)
req.Header.Add("Access-Control-Request-Headers", strings.Repeat(",", http.DefaultMaxHeaderBytes))
handler := Handler(Options{})(testHandler)
b.ReportAllocs()
b.ResetTimer()
for range b.N {
res := httptest.NewRecorder()
handler.ServeHTTP(res, req)
}
}
go test -run '^$' -bench . -count 8 > bench.out
benchstat bench.out
goos: darwin
goarch: amd64
pkg: whatever
cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
│ bench.out │
│ sec/op │
Preflight-8 1.477µ ± 2%
PreflightAdversarialACRH-8 4.890m ± 4%
geomean 84.97µ
│ bench.out │
│ B/op │
Preflight-8 1.133Ki ± 0%
PreflightAdversarialACRH-8 17.00Mi ± 0%
geomean 140.4Ki
│ bench.out │
│ allocs/op │
Preflight-8 15.00 ± 0%
PreflightAdversarialACRH-8 15.00 ± 0%
geomean
Impact
This behaviour could be abused by attackers to produce undue load on the middleware/server as an attempt to cause a denial of service. Moreover, because CORS middleware occurs before authentication, attackers wouldn't even need to be authenticated. Sure, most WAFs would likely drop those malicious preflight requests, but not all servers sit behind a WAF.
Solution
See https://github.com/jub0bs/cors/blob/b23eccc884c252107c2c8bd15de090706b6c2759/internal/headers/sortedset.go#L52 for inspiration.
Problem
This package (v1.2.1 and possibly earlier versions) suffers from a similar (though less severe) form of rs/cors#170. Processing a preflight request with a maliciously long
Access-Control-Request-Headersheader indeed requires a relatively long time and causes a lot of undue heap allocations. For example, processing a single malicious preflight request whose ACRH header comprises 1MiB's worth of commas takes about 5ms and allocates about 17 MiB:Impact
This behaviour could be abused by attackers to produce undue load on the middleware/server as an attempt to cause a denial of service. Moreover, because CORS middleware occurs before authentication, attackers wouldn't even need to be authenticated. Sure, most WAFs would likely drop those malicious preflight requests, but not all servers sit behind a WAF.
Solution
See https://github.com/jub0bs/cors/blob/b23eccc884c252107c2c8bd15de090706b6c2759/internal/headers/sortedset.go#L52 for inspiration.