From d55b41080062915e728b6afb75f5623927f100f7 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 4 Mar 2024 00:08:55 +0100 Subject: [PATCH] Use constant-time comparison for anti-csrf tokens This is probably completely overkill, but since anti-csrf tokens are secrets, they should be compared against untrusted inputs in constant time. --- internal/crypto/crypto.go | 5 +++++ internal/ui/middleware.go | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/crypto/crypto.go b/internal/crypto/crypto.go index 4c195508..0b0ab6c6 100644 --- a/internal/crypto/crypto.go +++ b/internal/crypto/crypto.go @@ -7,6 +7,7 @@ import ( "crypto/hmac" "crypto/rand" "crypto/sha256" + "crypto/subtle" "encoding/base64" "encoding/hex" "fmt" @@ -60,3 +61,7 @@ func GenerateUUID() string { b := GenerateRandomBytes(16) return fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) } + +func ConstantTimeCmp(a, b string) bool { + return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1 +} diff --git a/internal/ui/middleware.go b/internal/ui/middleware.go index 79e433e9..3a4a55e5 100644 --- a/internal/ui/middleware.go +++ b/internal/ui/middleware.go @@ -10,6 +10,7 @@ import ( "net/http" "miniflux.app/v2/internal/config" + "miniflux.app/v2/internal/crypto" "miniflux.app/v2/internal/http/cookie" "miniflux.app/v2/internal/http/request" "miniflux.app/v2/internal/http/response/html" @@ -92,7 +93,7 @@ func (m *middleware) handleAppSession(next http.Handler) http.Handler { formValue := r.FormValue("csrf") headerValue := r.Header.Get("X-Csrf-Token") - if session.Data.CSRF != formValue && session.Data.CSRF != headerValue { + if !crypto.ConstantTimeCmp(session.Data.CSRF, formValue) && !crypto.ConstantTimeCmp(session.Data.CSRF, headerValue) { slog.Warn("Invalid or missing CSRF token", slog.Any("url", r.RequestURI), slog.String("form_csrf", formValue),