diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 4e45259687..f5e8f03ae2 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -521,6 +521,9 @@ INTERNAL_TOKEN = ;; Set the two-factor auth behavior. ;; Set to "enforced", to force users to enroll into Two-Factor Authentication, users without 2FA have no access to repositories via API or web. ;TWO_FACTOR_AUTH = +;; +;; The value of the X-Frame-Options HTTP header for HTML responses. Use "unset" to remove the header. +;X_FRAME_OPTIONS = SAMEORIGIN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1290,9 +1293,6 @@ LEVEL = Info ;; ;; headers to permit ;HEADERS = Content-Type,User-Agent -;; -;; set X-FRAME-OPTIONS header -;X_FRAME_OPTIONS = SAMEORIGIN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/modules/setting/cors.go b/modules/setting/cors.go index 5260887d9d..a4906b8ae3 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -15,13 +15,11 @@ var CORSConfig = struct { MaxAge time.Duration AllowCredentials bool Headers []string - XFrameOptions string }{ - AllowDomain: []string{"*"}, - Methods: []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}, - Headers: []string{"Content-Type", "User-Agent"}, - MaxAge: 10 * time.Minute, - XFrameOptions: "SAMEORIGIN", + AllowDomain: []string{"*"}, + Methods: []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}, + Headers: []string{"Content-Type", "User-Agent"}, + MaxAge: 10 * time.Minute, } func loadCorsFrom(rootCfg ConfigProvider) { diff --git a/modules/setting/security.go b/modules/setting/security.go index d60cfbbfc8..743df61681 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -14,6 +14,12 @@ import ( ) // Security settings +var Security = struct { + // TODO: move more settings to this struct in future + XFrameOptions string +}{ + XFrameOptions: "SAMEORIGIN", +} var ( InstallLock bool @@ -140,6 +146,13 @@ func loadSecurityFrom(rootCfg ConfigProvider) { PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false) SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20) + deprecatedSetting(rootCfg, "cors", "X_FRAME_OPTIONS", "security", "X_FRAME_OPTIONS", "v1.26.0") + if sec.HasKey("X_FRAME_OPTIONS") { + Security.XFrameOptions = sec.Key("X_FRAME_OPTIONS").MustString(Security.XFrameOptions) + } else { + Security.XFrameOptions = rootCfg.Section("cors").Key("X_FRAME_OPTIONS").MustString(Security.XFrameOptions) + } + twoFactorAuth := sec.Key("TWO_FACTOR_AUTH").String() switch twoFactorAuth { case "": diff --git a/routers/common/errpage.go b/routers/common/errpage.go index 4d24914bd2..b14ab8bcf8 100644 --- a/routers/common/errpage.go +++ b/routers/common/errpage.go @@ -32,7 +32,9 @@ func renderServerErrorPage(w http.ResponseWriter, req *http.Request, respCode in } httpcache.SetCacheControlInHeader(w.Header(), &httpcache.CacheControlOptions{NoTransform: true}) - w.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions) + if setting.Security.XFrameOptions != "unset" { + w.Header().Set(`X-Frame-Options`, setting.Security.XFrameOptions) + } tmplCtx := context.NewTemplateContext(req.Context(), req) tmplCtx["Locale"] = middleware.Locale(w, req) diff --git a/services/context/api.go b/services/context/api.go index a104d13588..abd1f9f67e 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -235,8 +235,6 @@ func APIContexter() func(http.Handler) http.Handler { } httpcache.SetCacheControlInHeader(ctx.Resp.Header(), &httpcache.CacheControlOptions{NoTransform: true}) - ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions) - next.ServeHTTP(ctx.Resp, ctx.Req) }) } diff --git a/services/context/context.go b/services/context/context.go index 394a78aa9d..ccd0057f59 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -196,7 +196,10 @@ func Contexter() func(next http.Handler) http.Handler { } httpcache.SetCacheControlInHeader(ctx.Resp.Header(), &httpcache.CacheControlOptions{NoTransform: true}) - ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions) + + if setting.Security.XFrameOptions != "unset" { + ctx.Resp.Header().Set(`X-Frame-Options`, setting.Security.XFrameOptions) + } ctx.Data["SystemConfig"] = setting.Config()