Browse Source

Enforce domain, host header validation against domain setting, Refactoring of PR #1866, Closes #1732

Torkel Ödegaard 10 years ago
parent
commit
34539c0c13

+ 4 - 0
conf/defaults.ini

@@ -29,6 +29,10 @@ http_port = 3000
 # The public facing domain name used to access grafana from a browser
 # The public facing domain name used to access grafana from a browser
 domain = localhost
 domain = localhost
 
 
+# Redirect to correct domain if host header does not match domain
+# Prevents DNS rebinding attacks
+enforce_domain = false
+
 # The full public facing url
 # The full public facing url
 root_url = %(protocol)s://%(domain)s:%(http_port)s/
 root_url = %(protocol)s://%(domain)s:%(http_port)s/
 
 

+ 4 - 0
conf/sample.ini

@@ -29,6 +29,10 @@
 # The public facing domain name used to access grafana from a browser
 # The public facing domain name used to access grafana from a browser
 ;domain = localhost
 ;domain = localhost
 
 
+# Redirect to correct domain if host header does not match domain
+# Prevents DNS rebinding attacks
+;enforce_domain = false
+
 # The full public facing url
 # The full public facing url
 ;root_url = %(protocol)s://%(domain)s:%(http_port)s/
 ;root_url = %(protocol)s://%(domain)s:%(http_port)s/
 
 

+ 3 - 0
docs/sources/installation/configuration.md

@@ -72,6 +72,9 @@ Another way is put nginx or apache infront of Grafana and have them proxy reques
 This setting is only used in as a part of the root_url setting (see below). Important if you
 This setting is only used in as a part of the root_url setting (see below). Important if you
 use github or google oauth.
 use github or google oauth.
 
 
+### enforce_domain
+Redirect to correct domain if host header does not match domain. Prevents DNS rebinding attacks. Default is false.
+
 ### root_url
 ### root_url
 This is the full url used to access grafana from a web browser. This is important if you use
 This is the full url used to access grafana from a web browser. This is important if you use
 google or github oauth authentication (for the callback url to be correct).
 google or github oauth authentication (for the callback url to be correct).

+ 4 - 0
pkg/cmd/web.go

@@ -40,6 +40,10 @@ func newMacaron() *macaron.Macaron {
 		Delims:     macaron.Delims{Left: "[[", Right: "]]"},
 		Delims:     macaron.Delims{Left: "[[", Right: "]]"},
 	}))
 	}))
 
 
+	if setting.EnforceDomain {
+		m.Use(middleware.ValidateHostHeader(setting.Domain))
+	}
+
 	m.Use(middleware.GetContextHandler())
 	m.Use(middleware.GetContextHandler())
 	m.Use(middleware.Sessioner(&setting.SessionOptions))
 	m.Use(middleware.Sessioner(&setting.SessionOptions))
 
 

+ 0 - 10
pkg/middleware/middleware.go

@@ -34,16 +34,6 @@ func GetContextHandler() macaron.Handler {
 			AllowAnonymous: false,
 			AllowAnonymous: false,
 		}
 		}
 
 
-		h := ctx.Req.Host
-		if i := strings.Index(h, ":"); i >= 0 {
-			h = h[:i]
-		}
-
-		if !strings.EqualFold(h, setting.Domain) {
-			ctx.Redirect(strings.TrimSuffix(setting.AppUrl, "/")+ctx.Req.RequestURI, 301)
-			return
-		}
-
 		// the order in which these are tested are important
 		// the order in which these are tested are important
 		// look for api key in Authorization header first
 		// look for api key in Authorization header first
 		// then init session and look for userId in session
 		// then init session and look for userId in session

+ 22 - 0
pkg/middleware/validate_host.go

@@ -0,0 +1,22 @@
+package middleware
+
+import (
+	"strings"
+
+	"github.com/Unknwon/macaron"
+	"github.com/grafana/grafana/pkg/setting"
+)
+
+func ValidateHostHeader(domain string) macaron.Handler {
+	return func(c *macaron.Context) {
+		h := c.Req.Host
+		if i := strings.Index(h, ":"); i >= 0 {
+			h = h[:i]
+		}
+
+		if !strings.EqualFold(h, domain) {
+			c.Redirect(strings.TrimSuffix(setting.AppUrl, "/")+c.Req.RequestURI, 301)
+			return
+		}
+	}
+}

+ 2 - 1
pkg/setting/setting.go

@@ -65,6 +65,7 @@ var (
 	RouterLogging      bool
 	RouterLogging      bool
 	StaticRootPath     string
 	StaticRootPath     string
 	EnableGzip         bool
 	EnableGzip         bool
+	EnforceDomain      bool
 
 
 	// Security settings.
 	// Security settings.
 	SecretKey          string
 	SecretKey          string
@@ -355,10 +356,10 @@ func NewConfigContext(args *CommandLineArgs) {
 	Domain = server.Key("domain").MustString("localhost")
 	Domain = server.Key("domain").MustString("localhost")
 	HttpAddr = server.Key("http_addr").MustString("0.0.0.0")
 	HttpAddr = server.Key("http_addr").MustString("0.0.0.0")
 	HttpPort = server.Key("http_port").MustString("3000")
 	HttpPort = server.Key("http_port").MustString("3000")
-
 	StaticRootPath = makeAbsolute(server.Key("static_root_path").String(), HomePath)
 	StaticRootPath = makeAbsolute(server.Key("static_root_path").String(), HomePath)
 	RouterLogging = server.Key("router_logging").MustBool(false)
 	RouterLogging = server.Key("router_logging").MustBool(false)
 	EnableGzip = server.Key("enable_gzip").MustBool(false)
 	EnableGzip = server.Key("enable_gzip").MustBool(false)
+	EnforceDomain = server.Key("enforce_domain").MustBool(false)
 
 
 	security := Cfg.Section("security")
 	security := Cfg.Section("security")
 	SecretKey = security.Key("secret_key").String()
 	SecretKey = security.Key("secret_key").String()