As the definition of CSRF says
A CSRF token is a secure random token (e.g., synchronizer token or
challenge token) that is used to prevent CSRF attacks. The token needs
to be unique per user session and should be of large random value to
make it difficult to guess. A CSRF secure application assigns a unique
CSRF token for every user session.
it protects BE to be sure the posted that to the BE comes from a form generated by BE unless anybody can post data to BE from any source.
for example in a login form, a hacker could write a code to try several combinations ( of course drupal has a max retry policy which prevents users to try the wrong password more than 5 times and there is flood detection in drupal that prevent brute force attacking). But still, forms without CSRF protection are good places for bots and spammers to post data to the side several times.
So it's better if your forms are open to anonymous protect them honeypot and a human detection solution ( captcha, Recaptcha, Recaptcha 3 math captcha, etc).
additionally, having Security Kit module make it more secure.
Update part after I noticed it's happening for logged in users
for the reasons I mentioned above, particularly to have better caching functionalities, for an anonymous user, it does not get refreshed.
But for logged-in user after some checking in the code level I figure out it's not a bug.
it's generated based on the form_id and until you have not submitted the form it will be the same and refreshing does not generate a new one. So, form_token
and form_build_id
are things that protects form from.
for reference and get more take a look on :
// Add a token, based on either #token or form_id, to any form displayed to
// authenticated users. This ensures that any submitted form was actually
// requested previously by the user and protects against cross site request
// forgeries.
// This does not apply to programmatically submitted forms. Furthermore,
// since tokens are session-bound and forms displayed to anonymous users are
// very likely cached, we cannot assign a token for them.
// During installation, there is no $user yet.
// Form constructors may explicitly set #token to FALSE when cross site
// request forgery is irrelevant to the form, such as search forms.
if ($form_state
->isProgrammed() || isset($form['#token']) && $form['#token'] === FALSE) {
unset($form['#token']);
}
else {
$form['#cache']['contexts'][] = 'user.roles:authenticated';
if ($user && $user
->isAuthenticated()) {
// Generate a public token and placeholder based on the form ID.
$placeholder = 'form_token_placeholder_' . Crypt::hashBase64($form_id);
$form['#token'] = $placeholder;
$form['form_token'] = [
'#id' => Html::getUniqueId('edit-' . $form_id . '-form-token'),
'#type' => 'token',
'#default_value' => $placeholder,
// Form processing and validation require this value. Ensure the
// submitted form value appears literally, regardless of custom #tree
// and #parents being set elsewhere.
'#parents' => [
'form_token',
],
Reference : https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Form%21FormBuilder.php/function/FormBuilder%3A%3AprepareForm/9.3.x