Form protection tool
The TYPO3 Core provides a generic way of protecting forms against cross-site request forgery (CSRF).
Attention
This requires a logged-in user whether in frontend or backend. CSRF
protection is not supported for anonymous users. Without a logged-in user
the token will always be dummy
. See 77403
for details.
For each form in the backend/frontend (or link that changes some data), create a token and insert it as a hidden form element. The name of the form element does not matter; you only need it to get the form token for verifying it.
Examples
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Controller;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
final class FormProtectionExample
{
public function __construct(
private readonly FormProtectionFactory $formProtectionFactory,
) {}
public function handleRequest(ServerRequestInterface $request): ResponseInterface
{
$formProtection = $this->formProtectionFactory->createFromRequest($request);
$formToken = $formProtection->generateToken('BE user setup', 'edit');
$content = '<input type="hidden" name="formToken" value="' . $formToken . '">';
// ... some more logic ...
}
}
The three parameters of the generate
method:
$form
Name $action
(optional)$form
(optional)Instance Name
can be arbitrary strings, but they should make the form token as specific as
possible. For different forms (for example, BE user setup and editing a
tt_
record) or different records (with different UIDs) from the
same table, those values should be different.
For editing a tt_
record, the call could look like this:
$formToken = $formProtection->generateToken('tt_content', 'edit', (string)$uid);
When processing the data that has been submitted by the form, you can check that the form token is valid like this:
if ($dataHasBeenSubmitted &&
$formProtection->validateToken(
$request->getParsedBody()['formToken'] ?? '',
'BE user setup',
'edit'
) ) {
// process the data
} else {
// No need to do anything here, as the backend form protection will
// create a flash message for an invalid token
}
As it is recommended to use Form
to auto-detect which type is needed, one can also create a specific type
directly:
// For backend
$formProtection = $this->formProtectionFactory->createFromType('backend');
// For frontend
$formProtection = $this->formProtectionFactory->createFromType('frontend');