mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
cmd/geth, cmd/utils, node, rpc: ignore direct ip(v4/6) addresses in rpc virtual hostnames check
This commit is contained in:
parent
5d0c42e35f
commit
543df3f69c
7 changed files with 36 additions and 29 deletions
|
|
@ -111,7 +111,7 @@ var (
|
||||||
utils.VMEnableDebugFlag,
|
utils.VMEnableDebugFlag,
|
||||||
utils.NetworkIdFlag,
|
utils.NetworkIdFlag,
|
||||||
utils.RPCCORSDomainFlag,
|
utils.RPCCORSDomainFlag,
|
||||||
utils.RPCAllowedHostsFlag,
|
utils.RPCVirtualHostsFlag,
|
||||||
utils.EthStatsURLFlag,
|
utils.EthStatsURLFlag,
|
||||||
utils.MetricsEnabledFlag,
|
utils.MetricsEnabledFlag,
|
||||||
utils.FakePoWFlag,
|
utils.FakePoWFlag,
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ var AppHelpFlagGroups = []flagGroup{
|
||||||
utils.IPCDisabledFlag,
|
utils.IPCDisabledFlag,
|
||||||
utils.IPCPathFlag,
|
utils.IPCPathFlag,
|
||||||
utils.RPCCORSDomainFlag,
|
utils.RPCCORSDomainFlag,
|
||||||
utils.RPCAllowedHostsFlag,
|
utils.RPCVirtualHostsFlag,
|
||||||
utils.JSpathFlag,
|
utils.JSpathFlag,
|
||||||
utils.ExecFlag,
|
utils.ExecFlag,
|
||||||
utils.PreloadJSFlag,
|
utils.PreloadJSFlag,
|
||||||
|
|
|
||||||
|
|
@ -383,10 +383,10 @@ var (
|
||||||
Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
|
Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
|
||||||
Value: "",
|
Value: "",
|
||||||
}
|
}
|
||||||
RPCAllowedHostsFlag = cli.StringFlag{
|
RPCVirtualHostsFlag = cli.StringFlag{
|
||||||
Name: "rpcallowedhosts",
|
Name: "rpcvhosts",
|
||||||
Usage: "Comma separated list of hostnames from which to accept requests (server enforced). Set to * to disable this protection.",
|
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Set to * to disable this protection.",
|
||||||
Value: "localhost,127.0.0.1",
|
Value: "localhost",
|
||||||
}
|
}
|
||||||
RPCApiFlag = cli.StringFlag{
|
RPCApiFlag = cli.StringFlag{
|
||||||
Name: "rpcapi",
|
Name: "rpcapi",
|
||||||
|
|
@ -682,7 +682,7 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) {
|
||||||
cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
|
cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.HTTPHosts = splitAndTrim(ctx.GlobalString(RPCAllowedHostsFlag.Name))
|
cfg.HTTPVirtualHostnames = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// setWS creates the WebSocket RPC listener interface string from the set
|
// setWS creates the WebSocket RPC listener interface string from the set
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allowedHosts := api.node.config.HTTPHosts
|
allowedHosts := api.node.config.HTTPVirtualHostnames
|
||||||
if hosts != nil {
|
if hosts != nil {
|
||||||
allowedHosts = nil
|
allowedHosts = nil
|
||||||
for _, host := range strings.Split(*host, ",") {
|
for _, host := range strings.Split(*host, ",") {
|
||||||
|
|
|
||||||
|
|
@ -105,13 +105,14 @@ type Config struct {
|
||||||
// useless for custom HTTP clients.
|
// useless for custom HTTP clients.
|
||||||
HTTPCors []string `toml:",omitempty"`
|
HTTPCors []string `toml:",omitempty"`
|
||||||
|
|
||||||
// HTTPHosts is the list of hosts which are allowed on incoming requests.
|
// HTTPVirtualHostnames is the list of virtual hostnames which are allowed on incoming requests.
|
||||||
// This is by default {'localhost','127.0.0.1'}. Using this prevents attacks like
|
// This is by default {'localhost'}. Using this prevents attacks like
|
||||||
// DNS rebinding, which bypasses SOP by simply masquerading as being within the same
|
// DNS rebinding, which bypasses SOP by simply masquerading as being within the same
|
||||||
// origin. These attacks do not utilize CORS, since they are not cross-domain.
|
// origin. These attacks do not utilize CORS, since they are not cross-domain.
|
||||||
// By explicitly checking the Host-header, the server will not allow requests
|
// By explicitly checking the Host-header, the server will not allow requests
|
||||||
// made against the server with a malicious host domain.
|
// made against the server with a malicious host domain.
|
||||||
HTTPHosts []string `toml:",omitempty"`
|
// Requests using ip address directly are not affected
|
||||||
|
HTTPVirtualHostnames []string `toml:",omitempty"`
|
||||||
|
|
||||||
// HTTPModules is a list of API modules to expose via the HTTP RPC interface.
|
// HTTPModules is a list of API modules to expose via the HTTP RPC interface.
|
||||||
// If the module list is empty, all RPC API endpoints designated public will be
|
// If the module list is empty, all RPC API endpoints designated public will be
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error {
|
||||||
n.stopInProc()
|
n.stopInProc()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPHosts); err != nil {
|
if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHostnames); err != nil {
|
||||||
n.stopIPC()
|
n.stopIPC()
|
||||||
n.stopInProc()
|
n.stopInProc()
|
||||||
return err
|
return err
|
||||||
|
|
@ -395,7 +395,7 @@ func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors
|
||||||
}
|
}
|
||||||
go rpc.NewHTTPServer(cors, allowedHosts, handler).Serve(listener)
|
go rpc.NewHTTPServer(cors, allowedHosts, handler).Serve(listener)
|
||||||
n.log.Info(fmt.Sprintf("HTTP endpoint opened: http://%s", endpoint))
|
n.log.Info(fmt.Sprintf("HTTP endpoint opened: http://%s", endpoint))
|
||||||
n.log.Info(fmt.Sprintf("HTTP config: cors %v, hosts%v", cors, allowedHosts))
|
n.log.Info(fmt.Sprintf("HTTP config: cors %v, vhosts%v", cors, allowedHosts))
|
||||||
// All listeners booted successfully
|
// All listeners booted successfully
|
||||||
n.httpEndpoint = endpoint
|
n.httpEndpoint = endpoint
|
||||||
n.httpListener = listener
|
n.httpListener = listener
|
||||||
|
|
|
||||||
36
rpc/http.go
36
rpc/http.go
|
|
@ -170,10 +170,6 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
srv.ServeSingleRequest(codec, OptionMethodInvocation)
|
srv.ServeSingleRequest(codec, OptionMethodInvocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseHost(hostport string) string {
|
|
||||||
return strings.ToLower(strings.Split(hostport, ":")[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateRequest returns a non-zero response code and error message if the
|
// validateRequest returns a non-zero response code and error message if the
|
||||||
// request is invalid.
|
// request is invalid.
|
||||||
func validateRequest(r *http.Request) (int, error) {
|
func validateRequest(r *http.Request) (int, error) {
|
||||||
|
|
@ -220,21 +216,31 @@ type hostHandler struct {
|
||||||
// ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler
|
// ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler
|
||||||
func (h *hostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *hostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if r.Host != "" {
|
// if r.Host is not set, we can continue serving since a browser would set the Host header
|
||||||
hostpart := parseHost(r.Host)
|
if r.Host == "" {
|
||||||
requestAllowed := false
|
h.next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
host, _, err := net.SplitHostPort(r.Host)
|
||||||
|
if err != nil {
|
||||||
|
// Either invalid (too many colons) or no port specified
|
||||||
|
host = r.Host
|
||||||
|
}
|
||||||
|
if ipAddr := net.ParseIP(host); ipAddr != nil {
|
||||||
|
// It's an IP address, we can serve that
|
||||||
|
h.next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
// Not an ip address, but a hostname. Need to validate
|
||||||
for _, allowedHost := range h.AllowedHosts {
|
for _, allowedHost := range h.AllowedHosts {
|
||||||
if strings.ToLower(allowedHost) == hostpart || allowedHost == "*" {
|
if strings.ToLower(allowedHost) == strings.ToLower(host) || allowedHost == "*" {
|
||||||
requestAllowed = true
|
h.next.ServeHTTP(w, r)
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !requestAllowed {
|
|
||||||
http.Error(w, "invalid host specified", http.StatusForbidden)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h.next.ServeHTTP(w, r)
|
http.Error(w, "invalid host specified", http.StatusForbidden)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHostHandler(allowedHosts []string, next http.Handler) http.Handler {
|
func newHostHandler(allowedHosts []string, next http.Handler) http.Handler {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue