mirror of
https://github.com/gin-gonic/gin.git
synced 2026-04-29 23:23:18 +08:00
refactor(recovery): inline header prefix check and strengthen case tests
Drop the small hasHeaderPrefixFold helper and inline the len+EqualFold check in secureRequestDump for a simpler, single-site hardcoded replacement. Also switch the existing lowercase/mixed-case Authorization tests to write directly to r.Header (bypassing http.Header.Set canonicalization) so they actually exercise case-insensitive matching on the wire, and add uppercase Authorization plus lowercase/uppercase Proxy-Authorization cases.
This commit is contained in:
parent
3f1b179fdc
commit
528a95d48d
13
recovery.go
13
recovery.go
@ -100,22 +100,21 @@ func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc {
|
|||||||
func secureRequestDump(r *http.Request) string {
|
func secureRequestDump(r *http.Request) string {
|
||||||
httpRequest, _ := httputil.DumpRequest(r, false)
|
httpRequest, _ := httputil.DumpRequest(r, false)
|
||||||
lines := strings.Split(bytesconv.BytesToString(httpRequest), "\r\n")
|
lines := strings.Split(bytesconv.BytesToString(httpRequest), "\r\n")
|
||||||
|
const (
|
||||||
|
authPrefix = "Authorization:"
|
||||||
|
proxyPrefix = "Proxy-Authorization:"
|
||||||
|
)
|
||||||
for i, line := range lines {
|
for i, line := range lines {
|
||||||
switch {
|
switch {
|
||||||
case hasHeaderPrefixFold(line, "Authorization:"):
|
case len(line) >= len(authPrefix) && strings.EqualFold(line[:len(authPrefix)], authPrefix):
|
||||||
lines[i] = "Authorization: *"
|
lines[i] = "Authorization: *"
|
||||||
case hasHeaderPrefixFold(line, "Proxy-Authorization:"):
|
case len(line) >= len(proxyPrefix) && strings.EqualFold(line[:len(proxyPrefix)], proxyPrefix):
|
||||||
lines[i] = "Proxy-Authorization: *"
|
lines[i] = "Proxy-Authorization: *"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strings.Join(lines, "\r\n")
|
return strings.Join(lines, "\r\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasHeaderPrefixFold reports whether line begins with prefix, ignoring ASCII case.
|
|
||||||
func hasHeaderPrefixFold(line, prefix string) bool {
|
|
||||||
return len(line) >= len(prefix) && strings.EqualFold(line[:len(prefix)], prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultHandleRecovery(c *Context, _ any) {
|
func defaultHandleRecovery(c *Context, _ any) {
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -274,20 +274,32 @@ func TestSecureRequestDump(t *testing.T) {
|
|||||||
wantNotContain: "Bearer secret-token",
|
wantNotContain: "Bearer secret-token",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Bypass http.Header.Set canonicalization to put a lowercase
|
||||||
|
// header name on the wire and verify case-insensitive matching.
|
||||||
name: "authorization header lowercase",
|
name: "authorization header lowercase",
|
||||||
req: func() *http.Request {
|
req: func() *http.Request {
|
||||||
r, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
r, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
||||||
r.Header.Set("authorization", "some-secret")
|
r.Header["authorization"] = []string{"some-secret"}
|
||||||
return r
|
return r
|
||||||
}(),
|
}(),
|
||||||
wantContains: "Authorization: *",
|
wantContains: "Authorization: *",
|
||||||
wantNotContain: "some-secret",
|
wantNotContain: "some-secret",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "AUTHORIZATION header uppercase",
|
||||||
|
req: func() *http.Request {
|
||||||
|
r, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
||||||
|
r.Header["AUTHORIZATION"] = []string{"UPPER-SECRET"}
|
||||||
|
return r
|
||||||
|
}(),
|
||||||
|
wantContains: "Authorization: *",
|
||||||
|
wantNotContain: "UPPER-SECRET",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Authorization header mixed case",
|
name: "Authorization header mixed case",
|
||||||
req: func() *http.Request {
|
req: func() *http.Request {
|
||||||
r, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
r, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
||||||
r.Header.Set("AuThOrIzAtIoN", "token123")
|
r.Header["AuThOrIzAtIoN"] = []string{"token123"}
|
||||||
return r
|
return r
|
||||||
}(),
|
}(),
|
||||||
wantContains: "Authorization: *",
|
wantContains: "Authorization: *",
|
||||||
@ -303,6 +315,26 @@ func TestSecureRequestDump(t *testing.T) {
|
|||||||
wantContains: "Proxy-Authorization: *",
|
wantContains: "Proxy-Authorization: *",
|
||||||
wantNotContain: "Basic cHJveHk6c2VjcmV0",
|
wantNotContain: "Basic cHJveHk6c2VjcmV0",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "proxy-authorization header lowercase",
|
||||||
|
req: func() *http.Request {
|
||||||
|
r, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
||||||
|
r.Header["proxy-authorization"] = []string{"Basic bG93ZXI="}
|
||||||
|
return r
|
||||||
|
}(),
|
||||||
|
wantContains: "Proxy-Authorization: *",
|
||||||
|
wantNotContain: "Basic bG93ZXI=",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PROXY-AUTHORIZATION header uppercase",
|
||||||
|
req: func() *http.Request {
|
||||||
|
r, _ := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
||||||
|
r.Header["PROXY-AUTHORIZATION"] = []string{"Basic VVBQRVI="}
|
||||||
|
return r
|
||||||
|
}(),
|
||||||
|
wantContains: "Proxy-Authorization: *",
|
||||||
|
wantNotContain: "Basic VVBQRVI=",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "No Authorization header",
|
name: "No Authorization header",
|
||||||
req: func() *http.Request {
|
req: func() *http.Request {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user