瀏覽代碼

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

Torkel Ödegaard 10 年之前
父節點
當前提交
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
 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
 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
 ;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
 ;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
 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
 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).

+ 4 - 0
pkg/cmd/web.go

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

+ 0 - 10
pkg/middleware/middleware.go

@@ -34,16 +34,6 @@ func GetContextHandler() macaron.Handler {
 			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
 		// look for api key in Authorization header first
 		// 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
 	StaticRootPath     string
 	EnableGzip         bool
+	EnforceDomain      bool
 
 	// Security settings.
 	SecretKey          string
@@ -355,10 +356,10 @@ func NewConfigContext(args *CommandLineArgs) {
 	Domain = server.Key("domain").MustString("localhost")
 	HttpAddr = server.Key("http_addr").MustString("0.0.0.0")
 	HttpPort = server.Key("http_port").MustString("3000")
-
 	StaticRootPath = makeAbsolute(server.Key("static_root_path").String(), HomePath)
 	RouterLogging = server.Key("router_logging").MustBool(false)
 	EnableGzip = server.Key("enable_gzip").MustBool(false)
+	EnforceDomain = server.Key("enforce_domain").MustBool(false)
 
 	security := Cfg.Section("security")
 	SecretKey = security.Key("secret_key").String()