From e953c6abcf564e77a8a538e37ef5ddd28b38de9d Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sun, 28 Jan 2018 15:03:12 -0800 Subject: [PATCH] config: add stricter config parsing to avoid dangerous RPC auth combos In this commit, we add an additional constraint to the RPC configuration parsing. Before this commit, it was possible to start lnd with either RPC server listening on an external interface *without* authentication disabled. After this commit, if a user tries to start the RPC server listening on an external interface without any sort of RPC authentication, then the daemon will fail to start up. --- config.go | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/config.go b/config.go index ceae22f5..6bd9232f 100644 --- a/config.go +++ b/config.go @@ -464,7 +464,8 @@ func loadConfig() (*config, error) { cfg.RPCListeners = append(cfg.RPCListeners, addr) } - // Listen on the default interface/port if no REST listeners were specified. + // Listen on the default interface/port if no REST listeners were + // specified. if len(cfg.RESTListeners) == 0 { addr := fmt.Sprintf("localhost:%d", defaultRESTPort) cfg.RESTListeners = append(cfg.RESTListeners, addr) @@ -476,6 +477,18 @@ func loadConfig() (*config, error) { cfg.Listeners = append(cfg.Listeners, addr) } + // For each of the RPC listeners (REST+gRPC), we'll ensure that users + // have specified a safe combo for authentication. If not, we'll bail + // out with an error. + err := enforceSafeAuthentication(cfg.RPCListeners, !cfg.NoMacaroons) + if err != nil { + return nil, err + } + err = enforceSafeAuthentication(cfg.RESTListeners, !cfg.NoMacaroons) + if err != nil { + return nil, err + } + // Remove all Listeners if listening is disabled. if cfg.DisableListen { cfg.Listeners = nil @@ -867,3 +880,39 @@ func normalizeAddresses(addrs []string, defaultPort string) []string { } return result } + +// enforceSafeAuthentication enforces "safe" authentication taking into account +// the interfaces that the RPC servers are listening on, and if macaroons are +// activated or not. To project users from using dangerous config combinations, +// we'll prevent disabling authentication if the sever is listening on a public +// interface. +func enforceSafeAuthentication(addrs []string, macaroonsActive bool) error { + isLoopback := func(addr string) bool { + loopBackAddrs := []string{"localhost", "127.0.0.1"} + for _, loopback := range loopBackAddrs { + if strings.Contains(addr, loopback) { + return true + } + } + + return false + } + + // We'll now examine all addresses that this RPC server is listening + // on. If it's a localhost address, we'll skip it, otherwise, we'll + // return an error if macaroons are inactive. + for _, addr := range addrs { + if isLoopback(addr) { + continue + } + + if !macaroonsActive { + return fmt.Errorf("Detected RPC server listening on "+ + "publicly reachable interface %v with "+ + "authentication disabled! Refusing to start with "+ + "--no-macaroons specified.", addr) + } + } + + return nil +}