checker: flag the deprecated Public-Key-Pins (HPKP) header
This commit is contained in:
parent
a0fb42223b
commit
513a73f17f
3 changed files with 64 additions and 0 deletions
|
|
@ -24,6 +24,8 @@ relies on TLS for transport.
|
||||||
| `http.x_content_type_options` | Verifies that responses set X-Content-Type-Options: nosniff. | WARNING |
|
| `http.x_content_type_options` | Verifies that responses set X-Content-Type-Options: nosniff. | WARNING |
|
||||||
| `http.x_xss_protection` | Reports the legacy X-XSS-Protection header; warns on filtering mode (can introduce XSS), absent/`0` are fine, CSP is the real defense. | WARNING |
|
| `http.x_xss_protection` | Reports the legacy X-XSS-Protection header; warns on filtering mode (can introduce XSS), absent/`0` are fine, CSP is the real defense. | WARNING |
|
||||||
| `http.expect_ct` | Flags the deprecated Expect-CT header (Certificate Transparency is now enforced by mainstream clients; Mozilla recommends removing it). | WARNING |
|
| `http.expect_ct` | Flags the deprecated Expect-CT header (Certificate Transparency is now enforced by mainstream clients; Mozilla recommends removing it). | WARNING |
|
||||||
|
| `http.hpkp` | Flags the deprecated Public-Key-Pins (HPKP) header, which is unsupported by modern browsers; rely on Certificate Transparency and CAA records instead. | WARNING |
|
||||||
|
| `http.hpkp_report_only` | Flags the deprecated Public-Key-Pins-Report-Only (HPKP) header, which is unsupported by modern browsers; rely on Certificate Transparency and CAA records instead. | WARNING |
|
||||||
| `http.server_header` | Reports whether the Server header discloses the origin server software/version; a non-informative value is accepted. | INFO |
|
| `http.server_header` | Reports whether the Server header discloses the origin server software/version; a non-informative value is accepted. | INFO |
|
||||||
| `http.x_powered_by` | Reports the X-Powered-By header, which discloses the web server technology stack and should be removed. | INFO |
|
| `http.x_powered_by` | Reports the X-Powered-By header, which discloses the web server technology stack and should be removed. | INFO |
|
||||||
| `http.x_aspnet_version` | Reports the X-AspNet-Version header, which discloses the ASP.NET framework version and should be removed. | INFO |
|
| `http.x_aspnet_version` | Reports the X-AspNet-Version header, which discloses the ASP.NET framework version and should be removed. | INFO |
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,38 @@ func init() {
|
||||||
RegisterRule(disclosureHeaderRule("http.x_powered_by", "X-Powered-By", "the technologies used by the web server"))
|
RegisterRule(disclosureHeaderRule("http.x_powered_by", "X-Powered-By", "the technologies used by the web server"))
|
||||||
RegisterRule(disclosureHeaderRule("http.x_aspnet_version", "X-AspNet-Version", "the ASP.NET framework version"))
|
RegisterRule(disclosureHeaderRule("http.x_aspnet_version", "X-AspNet-Version", "the ASP.NET framework version"))
|
||||||
RegisterRule(disclosureHeaderRule("http.x_aspnetmvc_version", "X-AspNetMvc-Version", "the ASP.NET MVC version"))
|
RegisterRule(disclosureHeaderRule("http.x_aspnetmvc_version", "X-AspNetMvc-Version", "the ASP.NET MVC version"))
|
||||||
|
|
||||||
|
RegisterRule(deprecatedHPKPRule("http.hpkp", "Public-Key-Pins"))
|
||||||
|
RegisterRule(deprecatedHPKPRule("http.hpkp_report_only", "Public-Key-Pins-Report-Only"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// deprecatedHPKPRule builds a rule for the HTTP Public-Key-Pins (HPKP)
|
||||||
|
// headers. Key pinning was removed from Chromium in 2018 and is
|
||||||
|
// unsupported by all modern browsers; its operational brittleness made it
|
||||||
|
// a frequent cause of self-inflicted outages. Certificate Transparency
|
||||||
|
// and CAA records provide superior compromise detection, so any presence
|
||||||
|
// is reported as Warn ".deprecated" and absence is OK ".absent".
|
||||||
|
func deprecatedHPKPRule(code, header string) sdk.CheckRule {
|
||||||
|
return HeaderRule(HeaderRuleSpec{
|
||||||
|
Code: code,
|
||||||
|
Description: "Reports the presence of the deprecated " + header + " (HPKP) header, which is unsupported by modern browsers and should be removed.",
|
||||||
|
Header: header,
|
||||||
|
Inspect: func(_ string, _ HTTPProbe, _ sdk.CheckerOptions) []HeaderResult {
|
||||||
|
return []HeaderResult{{
|
||||||
|
Status: sdk.StatusWarn,
|
||||||
|
Suffix: "deprecated",
|
||||||
|
Message: header + " (HPKP) is deprecated. Key pinning was removed from Chromium in 2018 and is unsupported by modern browsers; rely on Certificate Transparency and CAA DNS records instead.",
|
||||||
|
Meta: map[string]any{"fix": "Remove the `" + header + "` header from your responses."},
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
OnMissing: func(_ HTTPProbe, _ sdk.CheckerOptions) []HeaderResult {
|
||||||
|
return []HeaderResult{{
|
||||||
|
Status: sdk.StatusOK,
|
||||||
|
Suffix: "absent",
|
||||||
|
Message: header + " is not set, which is correct (HPKP is deprecated).",
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information-disclosure headers --------------------------------------
|
// Information-disclosure headers --------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -353,6 +353,34 @@ func TestDisclosureHeaderRules(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHPKPRules(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
rule string
|
||||||
|
header string
|
||||||
|
}{
|
||||||
|
{"http.hpkp", "public-key-pins"},
|
||||||
|
{"http.hpkp_report_only", "public-key-pins-report-only"},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.rule, func(t *testing.T) {
|
||||||
|
// Absent → OK, since HPKP is deprecated.
|
||||||
|
states := runRule(t, ruleByName(t, c.rule), &HTTPData{Probes: []HTTPProbe{httpsProbe("a:443")}}, nil)
|
||||||
|
mustStatus(t, states, sdk.StatusOK)
|
||||||
|
if !hasCode(states, c.rule+".absent") {
|
||||||
|
t.Errorf("%s: missing absent code: %+v", c.rule, states)
|
||||||
|
}
|
||||||
|
// Present → Warn deprecated.
|
||||||
|
p := httpsProbe("a:443")
|
||||||
|
p.Headers[c.header] = `pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; max-age=5184000`
|
||||||
|
states = runRule(t, ruleByName(t, c.rule), &HTTPData{Probes: []HTTPProbe{p}}, nil)
|
||||||
|
mustStatus(t, states, sdk.StatusWarn)
|
||||||
|
if !hasCode(states, c.rule+".deprecated") {
|
||||||
|
t.Errorf("%s: missing deprecated code: %+v", c.rule, states)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSecurityHeaders_NoHTTPS(t *testing.T) {
|
func TestSecurityHeaders_NoHTTPS(t *testing.T) {
|
||||||
// Each header rule must emit Unknown when there are no successful HTTPS probes.
|
// Each header rule must emit Unknown when there are no successful HTTPS probes.
|
||||||
rules := []sdk.CheckRule{
|
rules := []sdk.CheckRule{
|
||||||
|
|
@ -366,6 +394,8 @@ func TestSecurityHeaders_NoHTTPS(t *testing.T) {
|
||||||
ruleByName(t, "http.x_powered_by"),
|
ruleByName(t, "http.x_powered_by"),
|
||||||
ruleByName(t, "http.x_aspnet_version"),
|
ruleByName(t, "http.x_aspnet_version"),
|
||||||
ruleByName(t, "http.x_aspnetmvc_version"),
|
ruleByName(t, "http.x_aspnetmvc_version"),
|
||||||
|
ruleByName(t, "http.hpkp"),
|
||||||
|
ruleByName(t, "http.hpkp_report_only"),
|
||||||
}
|
}
|
||||||
data := &HTTPData{Probes: []HTTPProbe{httpProbe("a:80")}}
|
data := &HTTPData{Probes: []HTTPProbe{httpProbe("a:80")}}
|
||||||
for _, r := range rules {
|
for _, r := range rules {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue