Form protection tool
Changed in version 12.1
Before TYPO3 v12.1, the Form
provided only static
methods to get the concrete form protection implementation. Since
TYPO3 v12.1, the Form
can be instantiated and
therefore injected into the constructor. The static methods are deprecated
and will be removed in TYPO3 v13.
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');