mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-19 06:27:38 +00:00
fix(proxy): keep Burst/Endpoints in ratelimit unmarshal; redact large truncated log bodies
- ratelimit: custom UnmarshalJSON temp struct only carried interval/req, silently dropping the configured 'burst' and 'endpoints' fields. Burst is consumed at checkRateLimit (burst allowance) but could never be set via config file. Carry all fields in the temp struct. - sanitization: a large non-parsable body was truncated before redaction, potentially leaking a secret in the first MaxLogBodySize bytes, and the truncation could split a multi-byte UTF-8 rune. Redact the retained prefix and truncate on a rune boundary (sanitizeTruncatedBody). - tests: TestRateLimitConfigUnmarshalKeepsBurstAndEndpoints, TestSanitizeTruncatedBodyRedactsAndKeepsUTF8, TestTruncateUTF8RuneBoundary.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
@@ -612,3 +613,39 @@ func BenchmarkSanitizeHeaders(b *testing.B) {
|
||||
sanitizeHeaders(headers)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProxyLoggingSecurityTestSuite) TestSanitizeTruncatedBodyRedactsAndKeepsUTF8() {
|
||||
// A large body whose JSON parse fails (malformed JSON) must still redact
|
||||
// sensitive fields in the retained prefix, and the truncation must not
|
||||
// cut a multi-byte UTF-8 codepoint.
|
||||
secret := "hunter2-S3cret"
|
||||
big := strings.Repeat("a", MaxLogBodySize+10)
|
||||
// Unterminated string -> JSON decode fails -> falls through to truncation.
|
||||
malformed := `{"password": "` + secret + `"` + big
|
||||
|
||||
result := sanitizeForLogging([]byte(malformed), "application/json")
|
||||
if strings.Contains(result, secret) {
|
||||
suite.T().Errorf("truncated body leaked secret: %q", result)
|
||||
}
|
||||
if !strings.Contains(result, RedactedPlaceholder) {
|
||||
suite.T().Errorf("expected redaction placeholder in %q", result)
|
||||
}
|
||||
if !utf8.ValidString(result) {
|
||||
suite.T().Errorf("result is not valid UTF-8: %q", result)
|
||||
}
|
||||
if !strings.HasSuffix(result, TruncatedSuffix) {
|
||||
suite.T().Errorf("expected truncated suffix in %q", result)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProxyLoggingSecurityTestSuite) TestTruncateUTF8RuneBoundary() {
|
||||
// A multi-byte rune straddling the byte cutoff must be backed off, not split.
|
||||
orig := strings.Repeat("a", MaxLogBodySize-1) + "界"
|
||||
out := truncateUTF8(orig, MaxLogBodySize)
|
||||
if !utf8.ValidString(out) {
|
||||
suite.T().Fatalf("truncateUTF8 produced invalid UTF-8: %x", out)
|
||||
}
|
||||
if len(out) != MaxLogBodySize-1 {
|
||||
suite.T().Fatalf("expected backoff to %d bytes, got %d", MaxLogBodySize-1, len(out))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user