The (anti) CSRF Token should protect user from executing a action on the website by clicking a link or a form that is created by an attacker.
In the application that I want to secure I can't use an existing framework and I can't use html forms everywhere and I can't use Javascript to set headers. The application often uses just simple links and this can not easily be changed.
Still I like to have CSRF protection and want to know if the following approach would be secure. The approach relies only on a strict samesite cookie.
It should work like this:
A) For users without session:
When the application is installed a strong random(256bit) secret is generated (called SHARED_SECRET
).
When a user visits the page the first time, a the cookie (with settings samesite=strict, secure, http-only, host-only) with the a strong random (128bit called R
) +TIMESTAMP
+SIGNATURE
is created. I call it CSRF_TOKEN
. The SIGNATURE
is defined as hmac_sha256(R+TIMESTAMP,SHARED_SECRET)
. Every page load or ajax request creates a new CSRF_TOKEN
and replaces the existing CSRF_TOKEN
.
If the user does a action e.g. by pressing a action link the CSRF_TOKEN
cookie is read on server side. The value of the CSRF_TOKEN
cookie is split into R
, TIMESTAMP
and SIGNATURE
and the SIGNATURE'
is calculated again using hmac(R+TIMESTAMP,SHARED_SECRET)
the result compared against the SIGNATURE
from the CSRF_TOKEN
.
If the signatures are equal (with a equal function save against timing attacks) and the timestamp is not older then ~15min and Sec-Fetch-Site
is not present or value equals same-origin
the action will be executed.
B) For users with session:
The session key is stored in cookie with (samesite=lax, secure, http-only, host-only) and a strong random csrf token is generated and stored in the CSRF_TOKEN
cookie (samesite=strict,secure, http-only, host-only) and within the server side session store.
For each action triggered by the user the session is loaded and CSRF_TOKEN
token is compared with the value stored in the session and if Sec-Fetch-Site
is present it's checked if the value equals same-origin
.
I guess with the good browser support for the samesite=strict and Sec-Fetch-Site
feature it may be a secure solution but maybe I missing something. Would it be secure CSRF protection?