Limit the length of logged HTTP response (#1778)
* Limit the length of logged HTTP response Fixes #1777 * Fix crash, add tests * Fix utf-8 truncation * move more logic into helper method * Add unit test for truncateBody https://github.com/letsencrypt/boulder/pull/1778
This commit is contained in:
parent
dc15f6a55e
commit
801626fb15
|
|
@ -373,8 +373,9 @@ func (va *ValidationAuthorityImpl) validateHTTP01(ctx context.Context, identifie
|
||||||
}
|
}
|
||||||
|
|
||||||
if expectedKeyAuth != payload {
|
if expectedKeyAuth != payload {
|
||||||
|
truncBody := truncateBody(payload)
|
||||||
errString := fmt.Sprintf("The key authorization file from the server did not match this challenge [%v] != [%v]",
|
errString := fmt.Sprintf("The key authorization file from the server did not match this challenge [%v] != [%v]",
|
||||||
expectedKeyAuth, string(body))
|
expectedKeyAuth, truncBody)
|
||||||
va.log.Info(fmt.Sprintf("%s for %s", errString, identifier))
|
va.log.Info(fmt.Sprintf("%s for %s", errString, identifier))
|
||||||
return validationRecords, &probs.ProblemDetails{
|
return validationRecords, &probs.ProblemDetails{
|
||||||
Type: probs.UnauthorizedProblem,
|
Type: probs.UnauthorizedProblem,
|
||||||
|
|
@ -385,6 +386,19 @@ func (va *ValidationAuthorityImpl) validateHTTP01(ctx context.Context, identifie
|
||||||
return validationRecords, nil
|
return validationRecords, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// truncateBody will cut off a string at 45 UTF-8 characters.
|
||||||
|
func truncateBody(str string) string {
|
||||||
|
count := 0
|
||||||
|
const max = 45
|
||||||
|
for index, _ := range str {
|
||||||
|
count++
|
||||||
|
if count > max {
|
||||||
|
return fmt.Sprintf("%s…", str[:index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
func (va *ValidationAuthorityImpl) validateTLSSNI01(ctx context.Context, identifier core.AcmeIdentifier, challenge core.Challenge) ([]core.ValidationRecord, *probs.ProblemDetails) {
|
func (va *ValidationAuthorityImpl) validateTLSSNI01(ctx context.Context, identifier core.AcmeIdentifier, challenge core.Challenge) ([]core.ValidationRecord, *probs.ProblemDetails) {
|
||||||
if identifier.Type != "dns" {
|
if identifier.Type != "dns" {
|
||||||
va.log.Info(fmt.Sprintf("Identifier type for TLS-SNI was not DNS: %s", identifier))
|
va.log.Info(fmt.Sprintf("Identifier type for TLS-SNI was not DNS: %s", identifier))
|
||||||
|
|
|
||||||
|
|
@ -541,6 +541,36 @@ func TestValidateHTTP(t *testing.T) {
|
||||||
test.AssertEquals(t, core.StatusValid, mockRA.lastAuthz.Challenges[0].Status)
|
test.AssertEquals(t, core.StatusValid, mockRA.lastAuthz.Challenges[0].Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateHTTPResponseDocument(t *testing.T) {
|
||||||
|
chall := core.HTTPChallenge01(accountKey)
|
||||||
|
setChallengeToken(&chall, core.NewToken())
|
||||||
|
|
||||||
|
hs := httpSrv(t, `a.StartOfLine.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.PastTruncationPoint.aaaaaaaaaaaaaaaaaaaa`)
|
||||||
|
port, err := getPort(hs)
|
||||||
|
test.AssertNotError(t, err, "failed to get test server port")
|
||||||
|
stats, _ := statsd.NewNoopClient()
|
||||||
|
va := NewValidationAuthorityImpl(&cmd.PortConfig{HTTPPort: port}, nil, nil, stats, clock.Default())
|
||||||
|
va.DNSResolver = &bdns.MockDNSResolver{}
|
||||||
|
mockRA := &MockRegistrationAuthority{}
|
||||||
|
va.RA = mockRA
|
||||||
|
|
||||||
|
defer hs.Close()
|
||||||
|
|
||||||
|
var authz = core.Authorization{
|
||||||
|
ID: core.NewToken(),
|
||||||
|
RegistrationID: 1,
|
||||||
|
Identifier: ident,
|
||||||
|
Challenges: []core.Challenge{chall},
|
||||||
|
}
|
||||||
|
va.validate(ctx, authz, 0)
|
||||||
|
|
||||||
|
test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status)
|
||||||
|
test.Assert(t, len(log.GetAllMatching("StartOfLine")) > 1, "Beginning of response body not logged")
|
||||||
|
test.Assert(t, len(log.GetAllMatching("…")) > 1, "Ellipsis not logged")
|
||||||
|
test.AssertEquals(t, len(log.GetAllMatching("PastTruncationPoint")), 0) // End of response body was logged
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// challengeType == "tls-sni-00" or "dns-00", since they're the same
|
// challengeType == "tls-sni-00" or "dns-00", since they're the same
|
||||||
func createChallenge(challengeType string) core.Challenge {
|
func createChallenge(challengeType string) core.Challenge {
|
||||||
chall := core.Challenge{
|
chall := core.Challenge{
|
||||||
|
|
@ -1008,6 +1038,27 @@ func TestCAAFailure(t *testing.T) {
|
||||||
test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status)
|
test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTruncateBody(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
Case string
|
||||||
|
Expected string
|
||||||
|
}{
|
||||||
|
{"", ""},
|
||||||
|
{"a", "a"},
|
||||||
|
{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa…"},
|
||||||
|
{"ááááááááááááááááááááááááááááááááááááááááááááá", "ááááááááááááááááááááááááááááááááááááááááááááá"},
|
||||||
|
{"áááááááááááááááááááááááááááááááááááááááááááááá", "ááááááááááááááááááááááááááááááááááááááááááááá…"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range testCases {
|
||||||
|
result := truncateBody(v.Case)
|
||||||
|
if result != v.Expected {
|
||||||
|
t.Errorf("got %q, expected %q", result, v.Expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type MockRegistrationAuthority struct {
|
type MockRegistrationAuthority struct {
|
||||||
lastAuthz *core.Authorization
|
lastAuthz *core.Authorization
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue