Form flood protection
Ban clients that submit a form faster than a real visitor plausibly would.
The extension ships a finisher for the TYPO3 Form Framework (EXT:form)
that reports every submission of a form to the firewall. An allow2ban rule
counts the submissions per client and bans the client once it crosses the
threshold; the middleware then rejects further requests
early, before TYPO3 boots.
The finisher counts every valid submission, not only suspicious ones: finishers run after the form validation, so rejected submissions are not counted. Unlike a honeypot or CAPTCHA, which target bots, it also stops real visitors who hammer a form. Use it alongside those measures, not instead of them.
Warning
An allow2ban ban blocks the client's IP address for the whole site, not just the form. Visitors behind a shared IP (company NAT, campus networks) count against the same limit and would be locked out together. Keep the threshold generous enough for that case.
Note
Requirements: typo3/cms-form must be installed, and the firewall
needs a persistent store (see Storage). With the default
InMemoryCache the counters reset on every request and the rule never
triggers; the extension logs a warning in that case.
Enable it
- In Admin Tools > Settings > Extension Configuration >
firewall, enable form flood protection. This registers an
allow2ban rule named
form-floodwith the configured threshold (default 5 submissions), period (default 60 seconds), and ban duration (default 1 hour). - In the form editor, add the Firewall: flood protection finisher to each form you want to protect.
Both steps are needed: without the rule, reported submissions are ignored; without the finisher, nothing reports. The client is identified by IP address, resolved with the same trusted-proxy handling as the rest of the firewall (see Trusted proxies).
Replace the default rule
For full control over the rule, define form-flood in
config/ yourself. A rule from the configuration
file always wins over the generated default:
$config->allow2ban->add(
'form-flood',
threshold: 3,
period: 120,
banSeconds: 7200,
// Fed by the finisher; the rule never matches a request on its own.
filter: static fn(): bool => false,
);
Give a form its own counter
By default every form using the finisher reports to the same form-flood
rule, so their submissions share one counter per client: a visitor filling
in several different forms counts towards a single limit, and the resulting
ban applies site-wide. To count a form on its own, point its finisher at a
separate allow2ban rule.
In the form editor, the Firewall: flood protection finisher has a
Allow2ban rule identifier field. Enter a name other than
form-flood (for example contact-form-flood) to give that form its own
counter. The rule must exist, so define it in
config/ (the extension configuration only
registers the default form-flood rule):
$config->allow2ban->add(
'contact-form-flood',
threshold: 3,
period: 120,
banSeconds: 7200,
// Fed by the finisher; the rule never matches a request on its own.
filter: static fn(): bool => false,
);
A submission reported to a rule name that is not defined is ignored, so a
typo in the field silently disables protection for that form; double-check
the name matches the rule in phirewall.php.
Change the rule from code
Before a submission is reported, the finisher dispatches the
\Flowd\ event with
the rule identifier the finisher resolved (the option above, or the default).
A listener can change it, for example to derive the rule from the form, or
set an empty identifier to skip the submission:
use Flowd\Typo3Firewall\Event\FloodProtectionFinisherTriggered;
final class UseStricterContactFormRule
{
public function __invoke(FloodProtectionFinisherTriggered $event): void
{
$event->ruleIdentifier = 'contact-form-flood';
}
}
Register the class as an event listener in the Services. of
your site package. The rule it points to must be defined in
config/.