CSRF tokens vs Nonce confusion - are they the same?
Nonce is usually some random string that is added to request just to change in unpredictable way the data, which is used to calculate the signature. So nonce usually is not used by any server-side business logic.
While CSRF-token is stored somewhere on server, passed to the client and need to be returned back to the server to compare. And if matches - then OK.
So in your case the better will be to save csrf token once in a session variable like
$_SESSION['csrf_token'] = bin2hex(random_bytes(16));
and use it unchanged during the session life in all forms you have in your application.
(If you don't have random_bytes()
, use random_compat to polyfill it.)
No, they're not the same.
Nonces prevent replay attacks (prevent eavesdropper from storing signed request and re-submitting it later, e.g. if Alice sends "Pay Bob $100", you don't want somebody to re-send that 100 times).
CSRF tokens patch HTML-specific weakness in authentication of users' action, where 3rd party website can submit forms with credentials of user viewing the site (e.g. JavaScript on evil.example.com submitting form to facebook.com using your browser, authenticated as you).
CSRF tokens need to be secret, otherwise attacker would have the missing piece required to forge a request.
Nonces don't have to be secret if they're signed with requester's secret (as long as attacker cannot replace one nonce with another).
You can allow replay of requests with CSRF tokens and still be secured against CSRF (you're interested whether that was intentional action by the user, but may not necessarily want to stop user from performing it many times).
In fact, that's very often useful property, e.g. allows users to use Back button and re-submit forms with corrected values. If you implement CSRF protection with Nonce-like mechanism, you'll get false alarms when users refresh submitted pages.
An easy way to prevent CSRF without Nonces is to put session ID in a hidden from field (not a value stored in the session, but ID of the session itself, the same that you store in the cookie [session_id()
in PHP]). When the form is submitted check that form's session ID matches ID in the cookie. That is enough for CSRF, since attacker cannot know value of the cookie (CSRF only allows attackers to blindly send cookies).