Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlessio Caiazza <376774-nolith@users.noreply.gitlab.com>2020-12-22 14:36:37 +0300
committerAlessio Caiazza <376774-nolith@users.noreply.gitlab.com>2020-12-22 14:36:37 +0300
commit5e99bfef6303000b1f7c98afb8d753818984c4df (patch)
tree6f24a24d3df38ac2d3dd655ea8ecfcde4b49ecf7
parent44ec9a4cfed7bba0ed59c555ab4476f315652b2a (diff)
parent6069a8a0047ed3ce3a0e1934c9a66324ef7cebde (diff)
Merge branch 'security-1-30-prometheus-labels' into '1-30-stable'
Reject all unknown http methods See merge request gitlab-org/security/gitlab-pages!10
-rw-r--r--app.go7
-rw-r--r--internal/rejectmethods/middleware.go30
-rw-r--r--internal/rejectmethods/middleware_test.go43
-rw-r--r--metrics/metrics.go7
-rw-r--r--test/acceptance/unknown_http_method_test.go23
5 files changed, 110 insertions, 0 deletions
diff --git a/app.go b/app.go
index a704ce00..d3716899 100644
--- a/app.go
+++ b/app.go
@@ -27,6 +27,7 @@ import (
"gitlab.com/gitlab-org/gitlab-pages/internal/httperrors"
"gitlab.com/gitlab-org/gitlab-pages/internal/logging"
"gitlab.com/gitlab-org/gitlab-pages/internal/netutil"
+ "gitlab.com/gitlab-org/gitlab-pages/internal/rejectmethods"
"gitlab.com/gitlab-org/gitlab-pages/internal/request"
"gitlab.com/gitlab-org/gitlab-pages/internal/source"
"gitlab.com/gitlab-org/gitlab-pages/metrics"
@@ -334,6 +335,12 @@ func (a *theApp) buildHandlerPipeline() (http.Handler, error) {
// Custom response headers
handler = a.customHeadersMiddleware(handler)
+ // This MUST be the last handler!
+ // This handler blocks unknown HTTP methods,
+ // being the last means it will be evaluated first
+ // preventing any operation on bogus requests.
+ handler = rejectmethods.NewMiddleware(handler)
+
return handler, nil
}
diff --git a/internal/rejectmethods/middleware.go b/internal/rejectmethods/middleware.go
new file mode 100644
index 00000000..e76fc383
--- /dev/null
+++ b/internal/rejectmethods/middleware.go
@@ -0,0 +1,30 @@
+package rejectmethods
+
+import (
+ "net/http"
+
+ "gitlab.com/gitlab-org/gitlab-pages/metrics"
+)
+
+var acceptedMethods = map[string]bool{
+ http.MethodGet: true,
+ http.MethodHead: true,
+ http.MethodPost: true,
+ http.MethodPut: true,
+ http.MethodPatch: true,
+ http.MethodConnect: true,
+ http.MethodOptions: true,
+ http.MethodTrace: true,
+}
+
+// NewMiddleware returns middleware which rejects all unknown http methods
+func NewMiddleware(handler http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if acceptedMethods[r.Method] {
+ handler.ServeHTTP(w, r)
+ } else {
+ metrics.RejectedRequestsCount.Inc()
+ http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
+ }
+ })
+}
diff --git a/internal/rejectmethods/middleware_test.go b/internal/rejectmethods/middleware_test.go
new file mode 100644
index 00000000..2921975a
--- /dev/null
+++ b/internal/rejectmethods/middleware_test.go
@@ -0,0 +1,43 @@
+package rejectmethods
+
+import (
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestNewMiddleware(t *testing.T) {
+ handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "OK\n")
+ })
+
+ middleware := NewMiddleware(handler)
+
+ acceptedMethods := []string{"GET", "HEAD", "POST", "PUT", "PATCH", "CONNECT", "OPTIONS", "TRACE"}
+ for _, method := range acceptedMethods {
+ t.Run(method, func(t *testing.T) {
+ tmpRequest, _ := http.NewRequest(method, "/", nil)
+ recorder := httptest.NewRecorder()
+
+ middleware.ServeHTTP(recorder, tmpRequest)
+
+ result := recorder.Result()
+
+ require.Equal(t, http.StatusOK, result.StatusCode)
+ })
+ }
+
+ t.Run("UNKNOWN", func(t *testing.T) {
+ tmpRequest, _ := http.NewRequest("UNKNOWN", "/", nil)
+ recorder := httptest.NewRecorder()
+
+ middleware.ServeHTTP(recorder, tmpRequest)
+
+ result := recorder.Result()
+
+ require.Equal(t, http.StatusMethodNotAllowed, result.StatusCode)
+ })
+}
diff --git a/metrics/metrics.go b/metrics/metrics.go
index db7cae9a..045ff26e 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -199,6 +199,13 @@ var (
Help: "The number of files per zip archive total count over time",
},
)
+
+ RejectedRequestsCount = prometheus.NewCounter(
+ prometheus.CounterOpts{
+ Name: "gitlab_pages_unknown_method_rejected_requests",
+ Help: "The number of requests with unknown HTTP method which were rejected",
+ },
+ )
)
// MustRegister collectors with the Prometheus client
diff --git a/test/acceptance/unknown_http_method_test.go b/test/acceptance/unknown_http_method_test.go
new file mode 100644
index 00000000..f454cb41
--- /dev/null
+++ b/test/acceptance/unknown_http_method_test.go
@@ -0,0 +1,23 @@
+package acceptance_test
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestUnknownHTTPMethod(t *testing.T) {
+ skipUnlessEnabled(t)
+ teardown := RunPagesProcess(t, *pagesBinary, listeners, "")
+ defer teardown()
+
+ req, err := http.NewRequest("UNKNOWN", listeners[0].URL(""), nil)
+ require.NoError(t, err)
+ req.Host = ""
+
+ resp, err := DoPagesRequest(t, req)
+ require.NoError(t, err)
+
+ require.Equal(t, http.StatusMethodNotAllowed, resp.StatusCode)
+}