Add client header check middleware

As an additional csrf protection for API requests
This commit is contained in:
Andrey Antukh
2025-09-30 12:33:12 +02:00
committed by Alejandro Alonso
parent 47d9c6f282
commit 2c1a8b59ba
5 changed files with 37 additions and 3 deletions

View File

@@ -189,7 +189,8 @@
(::ws/routes cfg)
["/api" {:middleware [[mw/cors]]}
["/api" {:middleware [[mw/cors]
[sec/client-header-check]]}
(::oidc/routes cfg)
(::rpc.doc/routes cfg)
(::rpc/routes cfg)]]]))

View File

@@ -37,3 +37,19 @@
:compile (fn [_ _]
(when (contains? cf/flags :sec-fetch-metadata-middleware)
wrap-sec-fetch-metadata))})
(defn- wrap-client-header-check
"Check for a penpot custom header to be present as additional CSRF
protection"
[handler]
(fn [request]
(let [client (yreq/get-header request "x-client")]
(if (some? client)
(handler request)
{::yres/status 403}))))
(def client-header-check
{:name ::client-header-check
:compile (fn [_ _]
(when (contains? cf/flags :client-header-check-middleware)
wrap-client-header-check))})

View File

@@ -44,4 +44,16 @@
(t/is (= 200 (::yres/status resp5)))
(t/is (= 403 (::yres/status resp6)))))
(t/deftest client-header-check
(let [request1 (mock-request :get "some")
request2 (mock-request :post nil)
handler (fn [request]
{::yres/status 200})
handler (#'sec/wrap-client-header-check handler)
resp1 (handler request1)
resp2 (handler request2)]
(t/is (= 200 (::yres/status resp1)))
(t/is (= 403 (::yres/status resp2)))))

View File

@@ -139,7 +139,11 @@
;; Security layer middleware that filters request by fetch
;; metadata headers
:sec-fetch-metadata-middleware})
:sec-fetch-metadata-middleware
;; Security layer middleware that check the precense of x-client
;; http headers and enables an addtional csrf protection
:client-header-check-middleware})
(def all-flags
(set/union email login varia))

View File

@@ -51,7 +51,8 @@
(defn default-headers
[]
{"x-frontend-version" (:full cfg/version)})
{"x-frontend-version" (:full cfg/version)
"x-client" (str "penpot-frontend/" (:full cfg/version))})
(defn fetch
[{:keys [method uri query headers body mode omit-default-headers credentials]