mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 06:03:48 +03:00
parent
5c51c1db2c
commit
f66493efef
2 changed files with 43 additions and 14 deletions
25
admin.go
25
admin.go
|
@ -318,7 +318,32 @@ func (admin AdminConfig) allowedOrigins(addr NetworkAddress) []*url.URL {
|
||||||
// messages. If the requested URI does not include an Internet host
|
// messages. If the requested URI does not include an Internet host
|
||||||
// name for the service being requested, then the Host header field MUST
|
// name for the service being requested, then the Host header field MUST
|
||||||
// be given with an empty value."
|
// be given with an empty value."
|
||||||
|
//
|
||||||
|
// UPDATE July 2023: Go broke this by patching a minor security bug in 1.20.6.
|
||||||
|
// Understandable, but frustrating. See:
|
||||||
|
// https://github.com/golang/go/issues/60374
|
||||||
|
// See also the discussion here:
|
||||||
|
// https://github.com/golang/go/issues/61431
|
||||||
|
//
|
||||||
|
// We can no longer conform to RFC 2616 Section 14.26 from either Go or curl
|
||||||
|
// in purity. (Curl allowed no host between 7.40 and 7.50, but now requires a
|
||||||
|
// bogus host; see https://superuser.com/a/925610.) If we disable Host/Origin
|
||||||
|
// security checks, the infosec community assures me that it is secure to do
|
||||||
|
// so, because:
|
||||||
|
// 1) Browsers do not allow access to unix sockets
|
||||||
|
// 2) DNS is irrelevant to unix sockets
|
||||||
|
//
|
||||||
|
// I am not quite ready to trust either of those external factors, so instead
|
||||||
|
// of disabling Host/Origin checks, we now allow specific Host values when
|
||||||
|
// accessing the admin endpoint over unix sockets. I definitely don't trust
|
||||||
|
// DNS (e.g. I don't trust 'localhost' to always resolve to the local host),
|
||||||
|
// and IP shouldn't even be used, but if it is for some reason, I think we can
|
||||||
|
// at least be reasonably assured that 127.0.0.1 and ::1 route to the local
|
||||||
|
// machine, meaning that a hypothetical browser origin would have to be on the
|
||||||
|
// local machine as well.
|
||||||
uniqueOrigins[""] = struct{}{}
|
uniqueOrigins[""] = struct{}{}
|
||||||
|
uniqueOrigins["127.0.0.1"] = struct{}{}
|
||||||
|
uniqueOrigins["::1"] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
uniqueOrigins[net.JoinHostPort("localhost", addr.port())] = struct{}{}
|
uniqueOrigins[net.JoinHostPort("localhost", addr.port())] = struct{}{}
|
||||||
uniqueOrigins[net.JoinHostPort("::1", addr.port())] = struct{}{}
|
uniqueOrigins[net.JoinHostPort("::1", addr.port())] = struct{}{}
|
||||||
|
|
|
@ -610,7 +610,7 @@ func AdminAPIRequest(adminAddr, method, uri string, headers http.Header, body io
|
||||||
}
|
}
|
||||||
origin := "http://" + parsedAddr.JoinHostPort(0)
|
origin := "http://" + parsedAddr.JoinHostPort(0)
|
||||||
if parsedAddr.IsUnixNetwork() {
|
if parsedAddr.IsUnixNetwork() {
|
||||||
origin = "http://unixsocket" // hack so that http.NewRequest() is happy
|
origin = "http://127.0.0.1" // bogus host is a hack so that http.NewRequest() is happy
|
||||||
}
|
}
|
||||||
|
|
||||||
// form the request
|
// form the request
|
||||||
|
@ -619,20 +619,24 @@ func AdminAPIRequest(adminAddr, method, uri string, headers http.Header, body io
|
||||||
return nil, fmt.Errorf("making request: %v", err)
|
return nil, fmt.Errorf("making request: %v", err)
|
||||||
}
|
}
|
||||||
if parsedAddr.IsUnixNetwork() {
|
if parsedAddr.IsUnixNetwork() {
|
||||||
// When listening on a unix socket, the admin endpoint doesn't
|
// We used to conform to RFC 2616 Section 14.26 which requires
|
||||||
// accept any Host header because there is no host:port for
|
// an empty host header when there is no host, as is the case
|
||||||
// a unix socket's address. The server's host check is fairly
|
// with unix sockets. However, Go required a Host value so we
|
||||||
// strict for security reasons, so we don't allow just any
|
// used a hack of a space character as the host (it would see
|
||||||
// Host header. For unix sockets, the Host header must be
|
// the Host was non-empty, then trim the space later). As of
|
||||||
// empty. Unfortunately, Go makes it impossible to make HTTP
|
// Go 1.20.6 (July 2023), this hack no longer works. See:
|
||||||
// requests with an empty Host header... except with this one
|
// https://github.com/golang/go/issues/60374
|
||||||
// weird trick. (Hopefully they don't fix it. It's already
|
// See also the discussion here:
|
||||||
// hard enough to use HTTP over unix sockets.)
|
// https://github.com/golang/go/issues/61431
|
||||||
//
|
//
|
||||||
// An equivalent curl command would be something like:
|
// After that, we now require a Host value of either 127.0.0.1
|
||||||
// $ curl --unix-socket caddy.sock http:/:$REQUEST_URI
|
// or ::1 if one is set. Above I choose to use 127.0.0.1. Even
|
||||||
req.URL.Host = " "
|
// though the value should be completely irrelevant (it could be
|
||||||
req.Host = ""
|
// "srldkjfsd"), if for some reason the Host *is* used, at least
|
||||||
|
// we can have some reasonable assurance it will stay on the local
|
||||||
|
// machine and that browsers, if they ever allow access to unix
|
||||||
|
// sockets, can still enforce CORS, ensuring it is still coming
|
||||||
|
// from the local machine.
|
||||||
} else {
|
} else {
|
||||||
req.Header.Set("Origin", origin)
|
req.Header.Set("Origin", origin)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue