From 3ad72fa35f8e326dbd6a82e5ba1833040ed29c6f Mon Sep 17 00:00:00 2001 From: Pawel Boguslawski Date: Fri, 2 Dec 2022 17:43:58 +0100 Subject: [PATCH 1/8] Protection against CSRF added Author-Change-Id: IB#1129006 --- go.mod | 1 + go.sum | 2 ++ modules/setting/cors.go | 14 ++++++++++++- routers/common/middleware.go | 40 +++++++++++++++++++++++++++++++++++- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index e06ccfe13d84f..2b92e64b0fade 100644 --- a/go.mod +++ b/go.mod @@ -235,6 +235,7 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect + github.com/rs/cors v1.8.2 // indirect github.com/rs/xid v1.4.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect diff --git a/go.sum b/go.sum index 9c99adfbe14cc..b6b5f743056b6 100644 --- a/go.sum +++ b/go.sum @@ -1360,6 +1360,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= diff --git a/modules/setting/cors.go b/modules/setting/cors.go index a843194ff981d..71670572f42fc 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -1,4 +1,4 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. +// Copyright 2022 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. @@ -8,8 +8,13 @@ import ( "time" "code.gitea.io/gitea/modules/log" + "github.com/rs/cors" ) +// Cors handles CORS requests and allows other middlewares +// to check whetcher request marches CORS allowed origins. +var Cors *cors.Cors + // CORSConfig defines CORS settings var CORSConfig = struct { Enabled bool @@ -33,6 +38,13 @@ func newCORSService() { } if CORSConfig.Enabled { + Cors = cors.New(cors.Options{ + AllowedOrigins: CORSConfig.AllowDomain, + AllowedMethods: CORSConfig.Methods, + AllowCredentials: CORSConfig.AllowCredentials, + MaxAge: int(CORSConfig.MaxAge.Seconds()), + }) + log.Info("CORS Service Enabled") } } diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 6ea1e1dfbe5ea..7d4961ffda840 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -1,4 +1,4 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. +// Copyright 2022 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. @@ -79,5 +79,43 @@ func Middlewares() []func(http.Handler) http.Handler { next.ServeHTTP(resp, req) }) }) + + // Add CSRF handler. + handlers = append(handlers, csrfHandler()) + return handlers } + +// csfrHandler blocks recognized CSRF attempts. +// WARNING: for this proctection to work, web browser compatible with +// Fetch Metadata Request Headers (https://w3c.github.io/webappsec-fetch-metadata) +// must be used. +func csrfHandler() func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + + // Put header names we use for CSRF recognition into Vary response header. + if setting.CORSConfig.Enabled { + resp.Header().Set("Vary", "Origin, Sec-Fetch-Site") + } else { + resp.Header().Set("Vary", "Sec-Fetch-Site") + } + + // Allow requests not recognized as CSRF. + secFetchSite := strings.ToLower(req.Header.Get("Sec-Fetch-Site")) + if req.Method == "GET" || // GET must not be used for changing state (CSRF resistant). + secFetchSite == "" || // Accept requests from clients without Fetch Metadata Request Headers support. + secFetchSite == "same-origin" || // Accept requests from own origin. + secFetchSite == "none" || // Accept requests initiated by user (i.e. using bookmark). + ((secFetchSite == "same-site" || secFetchSite == "cross-site") && // Accept cross site requests allowed by CORS. + setting.CORSConfig.Enabled && setting.Cors.OriginAllowed(req)) { + next.ServeHTTP(resp, req) + return + } + + // Forbid and log other requests as CSRF. + log.Error("CSRF rejected: METHOD=\"%s\", Origin=\"%s\", Sec-Fetch-Site=\"%s\"", req.Method, req.Header.Get("Origin"), secFetchSite) + http.Error(resp, http.StatusText(http.StatusForbidden), http.StatusForbidden) + }) + } +} From ce742376c7fb093d636b79a60557f34ce9558040 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 22 Dec 2022 16:02:37 +0000 Subject: [PATCH 2/8] fix headers and include head protection Signed-off-by: Andrew Thornton --- modules/setting/cors.go | 2 +- routers/common/middleware.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/setting/cors.go b/modules/setting/cors.go index f919e382968aa..e2231a13a0422 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/routers/common/middleware.go b/routers/common/middleware.go index c0ab7ebad2b43..2237379ffcb08 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package common @@ -92,7 +92,6 @@ func Middlewares() []func(http.Handler) http.Handler { func csrfHandler() func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - // Put header names we use for CSRF recognition into Vary response header. if setting.CORSConfig.Enabled { resp.Header().Set("Vary", "Origin, Sec-Fetch-Site") @@ -103,6 +102,7 @@ func csrfHandler() func(next http.Handler) http.Handler { // Allow requests not recognized as CSRF. secFetchSite := strings.ToLower(req.Header.Get("Sec-Fetch-Site")) if req.Method == "GET" || // GET must not be used for changing state (CSRF resistant). + req.Method == "HEAD" || // HEAD must not be used for changing state (CSRF resistant). secFetchSite == "" || // Accept requests from clients without Fetch Metadata Request Headers support. secFetchSite == "same-origin" || // Accept requests from own origin. secFetchSite == "none" || // Accept requests initiated by user (i.e. using bookmark). From a400c7700cf688265a30b50e2befa2d15255cd5e Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 22 Dec 2022 16:11:17 +0000 Subject: [PATCH 3/8] update go-licenses too Signed-off-by: Andrew Thornton --- assets/go-licenses.json | 5 +++++ go.mod | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/assets/go-licenses.json b/assets/go-licenses.json index c4b62475fd4bc..f259b88c57044 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -734,6 +734,11 @@ "path": "github.com/rivo/uniseg/LICENSE.txt", "licenseText": "MIT License\n\nCopyright (c) 2019 Oliver Kuederle\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, + { + "name": "github.com/rs/cors", + "path": "github.com/rs/cors/LICENSE", + "licenseText": "Copyright (c) 2014 Olivier Poitrey \u003crs@dailymotion.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" + }, { "name": "github.com/rs/xid", "path": "github.com/rs/xid/LICENSE", diff --git a/go.mod b/go.mod index da872481d2af7..6f5668132b45e 100644 --- a/go.mod +++ b/go.mod @@ -79,6 +79,7 @@ require ( github.com/pquerna/otp v1.3.0 github.com/prometheus/client_golang v1.13.0 github.com/quasoft/websspi v1.1.2 + github.com/rs/cors v1.8.2 github.com/santhosh-tekuri/jsonschema/v5 v5.0.1 github.com/sergi/go-diff v1.2.0 github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 @@ -246,7 +247,6 @@ require ( github.com/prometheus/procfs v0.8.0 // indirect github.com/rivo/uniseg v0.4.2 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect - github.com/rs/cors v1.8.2 // indirect github.com/rs/xid v1.4.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect From 2b20046f3f1f016f553770761d12e9c773e55ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bogus=C5=82awski?= Date: Thu, 22 Dec 2022 17:18:32 +0100 Subject: [PATCH 4/8] Update cors.go --- modules/setting/cors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setting/cors.go b/modules/setting/cors.go index f919e382968aa..e2231a13a0422 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting From c5f3abef8b1279af1cb5e68b1f93bf11e265c29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bogus=C5=82awski?= Date: Thu, 22 Dec 2022 17:21:05 +0100 Subject: [PATCH 5/8] Update middleware.go According to https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#javascript-guidance-for-auto-inclusion-of-csrf-tokens-as-an-ajax-request-header GET, HEAD and OPTIONS should not be used for changing state. --- routers/common/middleware.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/routers/common/middleware.go b/routers/common/middleware.go index c0ab7ebad2b43..0f22d2181c151 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package common @@ -102,7 +102,9 @@ func csrfHandler() func(next http.Handler) http.Handler { // Allow requests not recognized as CSRF. secFetchSite := strings.ToLower(req.Header.Get("Sec-Fetch-Site")) - if req.Method == "GET" || // GET must not be used for changing state (CSRF resistant). + if req.Method == "GET" || // GET, HEAD and OPTIONS must not be used for changing state (CSRF resistant). + req.Method == "HEAD" || + req.Method == "OPTIONS" || secFetchSite == "" || // Accept requests from clients without Fetch Metadata Request Headers support. secFetchSite == "same-origin" || // Accept requests from own origin. secFetchSite == "none" || // Accept requests initiated by user (i.e. using bookmark). From 5d3de60791da72078f22a6c90a6e5324893526e2 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 22 Dec 2022 16:55:44 +0000 Subject: [PATCH 6/8] refix copyright header Signed-off-by: Andrew Thornton --- routers/common/middleware.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 66d1ef2b120d5..24a21e2f67024 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -1,8 +1,4 @@ -<<<<<<< HEAD // Copyright 2019 The Gitea Authors. All rights reserved. -======= -// Copyright 2021 The Gitea Authors. All rights reserved. ->>>>>>> main-IB#1129006 // SPDX-License-Identifier: MIT package common From 42faf67123aedc6317f861c50e93250f8dc9da67 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 22 Dec 2022 16:57:04 +0000 Subject: [PATCH 7/8] Update routers/common/middleware.go --- routers/common/middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 24a21e2f67024..750f38bf235e3 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -1,4 +1,4 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. +// Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package common From 10ad1013c112506306b93c688258db731198a57e Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 22 Dec 2022 16:58:11 +0000 Subject: [PATCH 8/8] fix fmt Signed-off-by: Andrew Thornton --- modules/setting/cors.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/setting/cors.go b/modules/setting/cors.go index e2231a13a0422..f581a637317a0 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -7,6 +7,7 @@ import ( "time" "code.gitea.io/gitea/modules/log" + "github.com/rs/cors" )