I want to implement fields and validations for CSRF using Forms. For example, it looks like this.
// myForm
//$csrf = new Hidden($this->security->getTokenKey());
$csrf = new Hidden('csrf');
$csrf->addValidator(
new Identical([
//'value' => $this->security->getToken(),
'value' => $this->security->getSessionToken(),
'message' => 'CSRF detect'
])
);
$this->add($csrf);
// volt
{# {{ form.render('csrf') }} #}
<!--
<input type="hidden" name="csrf" value="{{ security.getSessionToken() }}" />
-->
<input type="hidden" name="csrf" value="{{ security.getToken() }}" />
// controller
if (!$this->security->checkToken('csrf')) {
// abort
} else
if ($this->request->isPost()) {
$form = new myForm();
$data = $this->request->getPost();
if ($form->isValid($data)) {
// valid data
} else {
// invalid
}
}
//$this->security->getToken();
$form = new myForm($foo);
$this->view->setVar('form', $form);
But it doesn't quite work. For example, if I use getTokenKey() in myForm, it will become a new key name when I do new myForm() for validation, so isValid() will always return false. Similarly, if I use getToken(), the token value will also change, so isValid() never return true. I tried "'accepted' => $this->security->checkToken()", but I couldn't pass it because maybe my something wrong.
I can't proceed further with this, so I thought about another way.
The value changes each time getTokenKey() is called, so the key value is fixed and the token value uses the session. However, it is necessary to call getToken() somewhere, so I have no choice but to call it at the end and set it.
Also, if I create an element using render() in the view, the contents of $form will have a new token value at the time of setVar(), but the old token value will be displayed. However, this hasn't been fully validated and may be due to my environment (eg using firefox or something else). If you write it in HTML without using render(), it seems to work.
In this case, it doesn't seem to make sense to define CSRF fields in myForm. And, instead of isValid(), if I check CSRF using checkToken() by myself in the controller, it will be better without fixing the key name and reducing the security strength.
When I searched, I found that I made a base class of form and prepared a property of key name so that it would not be changed carelessly, but I feel that "the framework should prepare" But what do you guys think? I would like to have getSessionTokenKey() as well as getSessionToken(). Alternatively, checkToken() may accept a flag that uses the session value, or checkSessionToken() may be present.
If possible, I would like to define the validation in myForm (without fixing the key name, of course), and just use isValid(), and in view, I would like to use form.render('csrf').
Could anyone please tell me the best practices?