浏览代码

conf: add allowlist for accessing local network (#6842)

# Conflicts:
#	CHANGELOG.md
#	internal/assets/conf/conf_gen.go
#	internal/assets/templates/templates_gen.go
#	internal/conf/static.go
#	internal/conf/testdata/TestInit.golden.ini
Joe Chen 3 年之前
父节点
当前提交
eddae31ada

+ 2 - 0
conf/app.ini

@@ -169,6 +169,8 @@ COOKIE_SECURE = false
 ENABLE_LOGIN_STATUS_COOKIE = false
 ; The cookie name to store user login status.
 LOGIN_STATUS_COOKIE_NAME = login_status
+; A comma separated list of hostnames that are explicitly allowed to be accessed within the local network.
+LOCAL_NETWORK_ALLOWLIST =
 
 [email]
 ; Whether to enable the email service.

+ 1 - 0
conf/locale/locale_en-US.ini

@@ -1242,6 +1242,7 @@ config.security.cookie_secure = Enable secure cookie
 config.security.reverse_proxy_auth_user = Reverse proxy authentication header
 config.security.enable_login_status_cookie = Enable login status cookie
 config.security.login_status_cookie_name = Login status cookie
+config.security.local_network_allowlist = Local network allowlist
 
 config.email_config = Email configuration
 config.email.enabled = Enabled

+ 2 - 0
docs/dev/local_development.md

@@ -153,6 +153,8 @@ You would have to re-run this command after changing Go files, or any file under
 When you are actively working on HTML templates and static files during development, you may want to enable the following configuration to avoid recompiling and restarting Gogs every time you make a change to files under `template/` and `public/` directories:
 
 ```ini
+RUN_MODE = dev
+
 [server]
 LOAD_ASSETS_FROM_DISK = true
 ```

文件差异内容过多而无法显示
+ 240 - 240
internal/assets/conf/conf_gen.go


文件差异内容过多而无法显示
+ 1337 - 1337
internal/assets/public/public_gen.go


文件差异内容过多而无法显示
+ 153 - 153
internal/assets/templates/templates_gen.go


+ 1 - 0
internal/conf/static.go

@@ -103,6 +103,7 @@ var (
 		CookieSecure            bool
 		EnableLoginStatusCookie bool
 		LoginStatusCookieName   string
+		LocalNetworkAllowlist   []string `delim:","`
 
 		// Deprecated: Use Auth.ReverseProxyAuthenticationHeader instead, will be removed in 0.13.
 		ReverseProxyAuthenticationUser string

+ 1 - 0
internal/conf/testdata/TestInit.golden.ini

@@ -80,6 +80,7 @@ COOKIE_USERNAME=gogs_awesome
 COOKIE_SECURE=false
 ENABLE_LOGIN_STATUS_COOKIE=false
 LOGIN_STATUS_COOKIE_NAME=login_status
+LOCAL_NETWORK_ALLOWLIST=
 REVERSE_PROXY_AUTHENTICATION_USER=
 
 [email]

+ 2 - 1
internal/form/repo.go

@@ -12,6 +12,7 @@ import (
 	"github.com/unknwon/com"
 	"gopkg.in/macaron.v1"
 
+	"gogs.io/gogs/internal/conf"
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/netutil"
 )
@@ -69,7 +70,7 @@ func (f MigrateRepo) ParseRemoteAddr(user *db.User) (string, error) {
 			return "", db.ErrInvalidCloneAddr{IsURLError: true}
 		}
 
-		if netutil.IsLocalHostname(u.Hostname()) {
+		if netutil.IsLocalHostname(u.Hostname(), conf.Security.LocalNetworkAllowlist) {
 			return "", db.ErrInvalidCloneAddr{IsURLError: true}
 		}
 

+ 9 - 2
internal/netutil/netutil.go

@@ -47,8 +47,15 @@ func init() {
 	}
 }
 
-// IsLocalHostname returns true if given hostname is a known local address.
-func IsLocalHostname(hostname string) bool {
+// IsLocalHostname returns true if given hostname is resolved to local network
+// address, except exempted from the allowlist.
+func IsLocalHostname(hostname string, allowlist []string) bool {
+	for _, allow := range allowlist {
+		if hostname == allow {
+			return false
+		}
+	}
+
 	ips, err := net.LookupIP(hostname)
 	if err != nil {
 		return true

+ 7 - 3
internal/netutil/netutil_test.go

@@ -12,8 +12,9 @@ import (
 
 func TestIsLocalHostname(t *testing.T) {
 	tests := []struct {
-		hostname string
-		want     bool
+		hostname  string
+		allowlist []string
+		want      bool
 	}{
 		{hostname: "localhost", want: true},
 		{hostname: "127.0.0.1", want: true},
@@ -27,10 +28,13 @@ func TestIsLocalHostname(t *testing.T) {
 		{hostname: "gogs.io", want: false},
 		{hostname: "google.com", want: false},
 		{hostname: "165.232.140.255", want: false},
+
+		{hostname: "192.168.123.45", allowlist: []string{"10.0.0.17"}, want: true},
+		{hostname: "gogs.local", allowlist: []string{"gogs.local"}, want: false},
 	}
 	for _, test := range tests {
 		t.Run("", func(t *testing.T) {
-			assert.Equal(t, test.want, IsLocalHostname(test.hostname))
+			assert.Equal(t, test.want, IsLocalHostname(test.hostname, test.allowlist))
 		})
 	}
 }

+ 1 - 1
internal/route/repo/webhook.go

@@ -128,7 +128,7 @@ func validateWebhook(actor *db.User, l macaron.Locale, w *db.Webhook) (field, ms
 			return "PayloadURL", l.Tr("repo.settings.webhook.err_cannot_parse_payload_url", err), false
 		}
 
-		if netutil.IsLocalHostname(payloadURL.Hostname()) {
+		if netutil.IsLocalHostname(payloadURL.Hostname(), conf.Security.LocalNetworkAllowlist) {
 			return "PayloadURL", l.Tr("repo.settings.webhook.err_cannot_use_local_addresses"), false
 		}
 	}

+ 2 - 0
templates/admin/config.tmpl

@@ -206,6 +206,8 @@
 						<dd><i class="fa fa{{if .Security.EnableLoginStatusCookie}}-check{{end}}-square-o"></i></dd>
 						<dt>{{.i18n.Tr "admin.config.security.login_status_cookie_name"}}</dt>
 						<dd>{{.Security.LoginStatusCookieName}}</dd>
+						<dt>{{.i18n.Tr "admin.config.security.local_network_allowlist"}}</dt>
+						<dd><code>{{.Security.LocalNetworkAllowlist}}</code></dd>
 					</dl>
 				</div>
 

部分文件因为文件数量过多而无法显示