diff --git a/backend/src/app/http.clj b/backend/src/app/http.clj index 6be1ad500c..ffd227e12e 100644 --- a/backend/src/app/http.clj +++ b/backend/src/app/http.clj @@ -19,6 +19,7 @@ [app.http.errors :as errors] [app.http.management :as mgmt] [app.http.middleware :as mw] + [app.http.security :as sec] [app.http.session :as session] [app.http.websocket :as-alias ws] [app.main :as-alias main] @@ -167,6 +168,7 @@ [_ cfg] (rr/router [["" {:middleware [[mw/server-timing] + [sec/sec-fetch-metadata] [mw/params] [mw/format-response] [session/soft-auth cfg] diff --git a/backend/src/app/http/security.clj b/backend/src/app/http/security.clj new file mode 100644 index 0000000000..1834123c0a --- /dev/null +++ b/backend/src/app/http/security.clj @@ -0,0 +1,39 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.http.security + "Additional security layer middlewares" + (:require + [app.config :as cf] + [yetti.request :as yreq] + [yetti.response :as yres])) + +(def ^:private safe-methods + #{:get :head :options}) + +(defn- wrap-sec-fetch-metadata + "Sec-Fetch metadata security layer middleware" + [handler] + (fn [request] + (let [site (yreq/get-header request "sec-fetch-site")] + (cond + (= site "same-origin") + (handler request) + + (or (= site "same-site") + (= site "cross-site")) + (if (contains? safe-methods (yreq/method request)) + (handler request) + {::yres/status 403}) + + :else + (handler request))))) + +(def sec-fetch-metadata + {:name ::sec-fetch-metadata + :compile (fn [_ _] + (when (contains? cf/flags :sec-fetch-metadata-middleware) + wrap-sec-fetch-metadata))}) diff --git a/backend/test/backend_tests/http_middleware_security.clj b/backend/test/backend_tests/http_middleware_security.clj new file mode 100644 index 0000000000..d051e71d84 --- /dev/null +++ b/backend/test/backend_tests/http_middleware_security.clj @@ -0,0 +1,47 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns backend-tests.http-middleware-security + (:require + [app.http.security :as sec] + [clojure.test :as t] + [yetti.request :as yreq] + [yetti.response :as yres])) + +(defn- mock-request + [method value] + (reify yreq/IRequest + (method [_] + method) + (get-header [_ _] + value))) + +(t/deftest sec-fetch-metadata + (let [request1 (mock-request :get "same-origin") + request2 (mock-request :post "same-origin") + request3 (mock-request :get "same-site") + request4 (mock-request :post "same-site") + request5 (mock-request :get "cross-site") + request6 (mock-request :post "cross-site") + + handler (fn [request] + {::yres/status 200}) + handler (#'sec/wrap-sec-fetch-metadata handler) + resp1 (handler request1) + resp2 (handler request2) + resp3 (handler request3) + resp4 (handler request4) + resp5 (handler request5) + resp6 (handler request6)] + + (t/is (= 200 (::yres/status resp1))) + (t/is (= 200 (::yres/status resp2))) + (t/is (= 200 (::yres/status resp3))) + (t/is (= 403 (::yres/status resp4))) + (t/is (= 200 (::yres/status resp5))) + (t/is (= 403 (::yres/status resp6))))) + + diff --git a/common/src/app/common/flags.cljc b/common/src/app/common/flags.cljc index 0b1bfdb559..08babe3bc1 100644 --- a/common/src/app/common/flags.cljc +++ b/common/src/app/common/flags.cljc @@ -135,7 +135,11 @@ :subscriptions :subscriptions-old :frontend-binary-fills - :inspect-styles}) + :inspect-styles + + ;; Security layer middleware that filters request by fetch + ;; metadata headers + :sec-fetch-metadata-middleware}) (def all-flags (set/union email login varia))