va: add specific error for broken HTTP-01 redirects. (#4171)
Often folks will mis-configure their webserver to send an HTTP redirect missing a `/' between the FQDN and the path. E.g. in Apache using: Redirect / https://bad-redirect.org Instead of: Redirect / https://bad-redirect.org/ Will produce an invalid HTTP-01 redirect target like: https://bad-redirect.org.well-known/acme-challenge/xxxx This happens frequently enough we want to return a distinct error message for this case by detecting the redirect targets ending in ".well-known". After the "Simple HTTP-01" code landed this case was previously getting an error message of the form: > "Invalid hostname in redirect target, must end in IANA registered TLD" Resolves https://github.com/letsencrypt/boulder/issues/3606
This commit is contained in:
parent
7b49849f87
commit
2f3c703a72
|
|
@ -63,6 +63,43 @@ def rand_http_chall(client):
|
|||
return d, c.chall
|
||||
raise Exception("No HTTP-01 challenge found for random domain authz")
|
||||
|
||||
def test_http_challenge_broken_redirect():
|
||||
"""
|
||||
test_http_challenge_broken_redirect tests that a common webserver
|
||||
mis-configuration receives the correct specialized error message when attempting
|
||||
an HTTP-01 challenge.
|
||||
"""
|
||||
client = chisel2.make_client()
|
||||
|
||||
# Create an authz for a random domain and get its HTTP-01 challenge token
|
||||
d, chall = rand_http_chall(client)
|
||||
token = chall.encode("token")
|
||||
|
||||
# Create a broken HTTP redirect similar to a sort we see frequently "in the wild"
|
||||
challengePath = "/.well-known/acme-challenge/{0}".format(token)
|
||||
redirect = "http://{0}.well-known/acme-challenge/bad-bad-bad".format(d)
|
||||
challSrv.add_http_redirect(
|
||||
challengePath,
|
||||
redirect)
|
||||
|
||||
# Expect the specialized error message
|
||||
expectedError = "Fetching {0}: Invalid host in redirect target \"{1}.well-known\". Check webserver config for missing '/' in redirect target.".format(redirect, d)
|
||||
|
||||
# NOTE(@cpu): Can't use chisel2.expect_problem here because it doesn't let
|
||||
# us interrogate the detail message easily.
|
||||
try:
|
||||
chisel2.auth_and_issue([d], client=client, chall_type="http-01")
|
||||
except acme_errors.ValidationError as e:
|
||||
for authzr in e.failed_authzrs:
|
||||
c = chisel2.get_chall(authzr, challenges.HTTP01)
|
||||
error = c.error
|
||||
if error is None or error.typ != "urn:ietf:params:acme:error:connection":
|
||||
raise Exception("Expected connection prob, got %s" % (error.__str__()))
|
||||
if error.detail != expectedError:
|
||||
raise Exception("Expected prob detail %s, got %s" % (expectedError, error.detail))
|
||||
|
||||
challSrv.remove_http_redirect(challengePath)
|
||||
|
||||
def test_http_challenge_loop_redirect():
|
||||
client = chisel2.make_client()
|
||||
|
||||
|
|
|
|||
16
va/http.go
16
va/http.go
|
|
@ -314,6 +314,22 @@ func (va *ValidationAuthorityImpl) extractRequestTarget(req *http.Request) (stri
|
|||
"Only domain names are supported, not IP addresses", reqHost)
|
||||
}
|
||||
|
||||
// Often folks will misconfigure their webserver to send an HTTP redirect
|
||||
// missing a `/' between the FQDN and the path. E.g. in Apache using:
|
||||
// Redirect / https://bad-redirect.org
|
||||
// Instead of
|
||||
// Redirect / https://bad-redirect.org/
|
||||
// Will produce an invalid HTTP-01 redirect target like:
|
||||
// https://bad-redirect.org.well-known/acme-challenge/xxxx
|
||||
// This happens frequently enough we want to return a distinct error message
|
||||
// for this case by detecting the reqHost ending in ".well-known".
|
||||
if strings.HasSuffix(reqHost, ".well-known") {
|
||||
return "", 0, berrors.ConnectionFailureError(
|
||||
"Invalid host in redirect target %q. Check webserver config for missing '/' in redirect target.",
|
||||
reqHost,
|
||||
)
|
||||
}
|
||||
|
||||
if _, err := iana.ExtractSuffix(reqHost); err != nil {
|
||||
return "", 0, berrors.ConnectionFailureError(
|
||||
"Invalid hostname in redirect target, must end in IANA registered TLD")
|
||||
|
|
|
|||
|
|
@ -232,6 +232,13 @@ func TestExtractRequestTarget(t *testing.T) {
|
|||
},
|
||||
ExpectedError: errors.New("Invalid empty hostname in redirect target"),
|
||||
},
|
||||
{
|
||||
Name: "invalid .well-known hostname",
|
||||
Req: &http.Request{
|
||||
URL: mustURL(t, "https://my.webserver.is.misconfigured.well-known/acme-challenge/xxx"),
|
||||
},
|
||||
ExpectedError: errors.New(`Invalid host in redirect target "my.webserver.is.misconfigured.well-known". Check webserver config for missing '/' in redirect target.`),
|
||||
},
|
||||
{
|
||||
Name: "invalid non-iana hostname",
|
||||
Req: &http.Request{
|
||||
|
|
|
|||
Loading…
Reference in New Issue