From a8dc5a5a920e0ca5609065467df3fbd9d2bbc040 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 11 Jul 2019 21:15:32 +0800 Subject: [PATCH 1/3] support hsts --- modules/setting/hsts.go | 34 ++++++++++++++++++++++++++++++++++ modules/setting/setting.go | 1 + routers/routes/routes.go | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 modules/setting/hsts.go diff --git a/modules/setting/hsts.go b/modules/setting/hsts.go new file mode 100644 index 0000000000000..47fcbfa51f00a --- /dev/null +++ b/modules/setting/hsts.go @@ -0,0 +1,34 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package setting + +import "time" + +const ( + defaultMaxAge = time.Hour * 24 * 365 +) + +// HSTS is the configuration of HSTS +var HSTS = struct { + Enabled bool + MaxAge time.Duration + SendPreloadDirective bool +}{ + Enabled: false, + MaxAge: defaultMaxAge, + SendPreloadDirective: false, +} + +func configHSTS() { + sec := Cfg.Section("hsts") + // Check mailer setting. + if !sec.Key("ENABLED").MustBool() { + return + } + + HSTS.Enabled = true + HSTS.MaxAge = sec.Key("MAX_AGE").MustDuration(defaultMaxAge) + HSTS.SendPreloadDirective = sec.Key("SEND_PRELOAD_DIRECTIVE").MustBool() +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 7201f0619d4d3..a175ce91ad512 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -910,6 +910,7 @@ func NewContext() { newCron() newGit() + configHSTS() sec = Cfg.Section("mirror") Mirror.MinInterval = sec.Key("MIN_INTERVAL").MustDuration(10 * time.Minute) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index ec57e8f5fdac7..95bc9af476ed1 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -10,6 +10,7 @@ import ( "net/http" "os" "path" + "strconv" "text/template" "time" @@ -102,6 +103,16 @@ func RouterHandler(level log.Level) func(ctx *macaron.Context) { } } +func createHeaderValueNew(maxAge time.Duration, sendPreloadDirective bool) string { + buf := bytes.NewBufferString("max-age=") + buf.WriteString(strconv.Itoa(int(maxAge.Seconds()))) + buf.WriteString("; includeSubDomains") + if sendPreloadDirective { + buf.WriteString("; preload") + } + return buf.String() +} + // NewMacaron initializes Macaron instance. func NewMacaron() *macaron.Macaron { gob.Register(&u2f.Challenge{}) @@ -131,6 +142,13 @@ func NewMacaron() *macaron.Macaron { if setting.Protocol == setting.FCGI { m.SetURLPrefix(setting.AppSubURL) } + if setting.HSTS.Enabled { + m.Use(func() macaron.Handler { + return func(ctx *macaron.Context) { + ctx.Resp.Header().Set("Strict-Transport-Security", createHeaderValueNew(setting.HSTS.MaxAge, setting.HSTS.SendPreloadDirective)) + } + }) + } m.Use(public.Custom( &public.Options{ SkipLogging: setting.DisableRouterLog, From 6a91b7a1ed2c237e84f5e94ea755cdd696d28e8d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 11 Jul 2019 22:46:12 +0800 Subject: [PATCH 2/3] remove wrong comment --- modules/setting/hsts.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/setting/hsts.go b/modules/setting/hsts.go index 47fcbfa51f00a..17814db9081c5 100644 --- a/modules/setting/hsts.go +++ b/modules/setting/hsts.go @@ -23,7 +23,6 @@ var HSTS = struct { func configHSTS() { sec := Cfg.Section("hsts") - // Check mailer setting. if !sec.Key("ENABLED").MustBool() { return } From e6d772fb2c81c2aee88a6d01c2b3281c5462ce4b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 12 Jul 2019 09:47:57 +0800 Subject: [PATCH 3/3] add a new param allow customize includeSubDomain in hsts --- custom/conf/app.ini.sample | 10 ++++++++++ docs/content/doc/advanced/config-cheat-sheet.en-us.md | 7 +++++++ docs/content/doc/advanced/config-cheat-sheet.zh-cn.md | 5 +++++ modules/setting/hsts.go | 3 +++ routers/routes/routes.go | 9 ++++++--- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index e44cc90a4bfbf..c315cb38f0562 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -787,3 +787,13 @@ IS_INPUT_FILE = false ENABLED = false ; If you want to add authorization, specify a token here TOKEN = + +[hsts] +; Enables hsts. True or false, default is false. +ENABLED = false +; Max age of the time, default is 365 days. +MAX_AGE = 8760h +; require sub domains use hsts +INCLUDE_SUB_DOMAINS = false +; send preload +SEND_PRELOAD_DIRECTIVE = false \ No newline at end of file diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 61905f8ad8d9e..0833583f212b5 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -501,6 +501,13 @@ Two special environment variables are passed to the render command: - `GITEA_PREFIX_SRC`, which contains the current URL prefix in the `src` path tree. To be used as prefix for links. - `GITEA_PREFIX_RAW`, which contains the current URL prefix in the `raw` path tree. To be used as prefix for image paths. +## HSTS (`hsts`) + +- ENABLED: **false** Enables hsts. True or false, default is false. +- MAX_AGE: **8760h** Max age of the time, default is 365 days. +- INCLUDE_SUB_DOMAINS: **false** require sub domains use hsts, default is false. +- SEND_PRELOAD_DIRECTIVE: **false** send preload, default is false. + ## Other (`other`) - `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index b9a16dd844caa..f2628248e8180 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -237,7 +237,12 @@ IS_INPUT_FILE = false - RENDER_COMMAND: 工具的命令行命令及参数。 - IS_INPUT_FILE: 输入方式是最后一个参数为文件路径还是从标准输入读取。 +## HSTS (`hsts`) +- ENABLED: **false** 是否启用 HSTS。默认为否。 +- MAX_AGE: **8760h** 最大时间,默认是 365 天。 +- INCLUDE_SUB_DOMAINS: **false** 是否包含子域名,默认为否。 +- SEND_PRELOAD_DIRECTIVE: **false** 是否预加载,默认为否。 ## Other (`other`) diff --git a/modules/setting/hsts.go b/modules/setting/hsts.go index 17814db9081c5..0fd2a0e89d2f4 100644 --- a/modules/setting/hsts.go +++ b/modules/setting/hsts.go @@ -14,10 +14,12 @@ const ( var HSTS = struct { Enabled bool MaxAge time.Duration + IncludeSubDomains bool SendPreloadDirective bool }{ Enabled: false, MaxAge: defaultMaxAge, + IncludeSubDomains: false, SendPreloadDirective: false, } @@ -29,5 +31,6 @@ func configHSTS() { HSTS.Enabled = true HSTS.MaxAge = sec.Key("MAX_AGE").MustDuration(defaultMaxAge) + HSTS.IncludeSubDomains = sec.Key("INCLUDE_SUB_DOMAINS").MustBool() HSTS.SendPreloadDirective = sec.Key("SEND_PRELOAD_DIRECTIVE").MustBool() } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 95bc9af476ed1..4dc6106ac151e 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -103,10 +103,12 @@ func RouterHandler(level log.Level) func(ctx *macaron.Context) { } } -func createHeaderValueNew(maxAge time.Duration, sendPreloadDirective bool) string { +func createHeaderValueNew(maxAge time.Duration, includeSubDomains, sendPreloadDirective bool) string { buf := bytes.NewBufferString("max-age=") buf.WriteString(strconv.Itoa(int(maxAge.Seconds()))) - buf.WriteString("; includeSubDomains") + if includeSubDomains { + buf.WriteString("; includeSubDomains") + } if sendPreloadDirective { buf.WriteString("; preload") } @@ -145,7 +147,8 @@ func NewMacaron() *macaron.Macaron { if setting.HSTS.Enabled { m.Use(func() macaron.Handler { return func(ctx *macaron.Context) { - ctx.Resp.Header().Set("Strict-Transport-Security", createHeaderValueNew(setting.HSTS.MaxAge, setting.HSTS.SendPreloadDirective)) + ctx.Resp.Header().Set("Strict-Transport-Security", + createHeaderValueNew(setting.HSTS.MaxAge, setting.HSTS.IncludeSubDomains, setting.HSTS.SendPreloadDirective)) } }) }