The Firewall extension protects your TYPO3 website against unwanted traffic,
bots, and attacks. It blocks or limits requests based on IP address, path,
headers, or other patterns, and bans clients after repeated abuse.
The extension is built on the phirewall package
and adds everything you need in TYPO3: the request middleware, a backend
module for block patterns, bans and statistics, ready-made rule presets,
and dashboard widgets.
Start with Quick start if you want a working firewall in five minutes.
Read Introduction to understand what the extension does and how it
relates to phirewall.
The extension adds a backend module under System >
Firewall. It is available to administrators only.
The module has four views. Switch between them with the View
dropdown in the module's doc-header:
Patterns manages the static block patterns.
Blocked keys lists the clients that rules have banned automatically.
Event log lists the recorded firewall events with their details.
Statistics shows how much traffic the firewall blocked over time.
Patterns
The Patterns view: the active pattern list next to the add and edit form.
This view manages the static block patterns. The extension always adds them
to the firewall as the blocklist rule typo3-blocklist, so they take
effect even when no configuration file exists (see Configuration).
Patterns are stored in the file config/system/phirewall.patterns.json
(classic installation: typo3conf/system/phirewall.patterns.json). The
extension configuration setting patternsDirectory moves the file and its
lock file to another directory, for example when config/system is
read-only at runtime; the directory must lie within the TYPO3 project
directory or BE/lockRootPath (see Configuration).
Every change takes effect on the next request. No deployment and no cache
flush are needed.
The pattern list
The Active Patterns list shows one row per pattern with its kind,
value, target, expiry date, creation date, and last change. A pattern that
has passed its expiry date is highlighted and no longer blocks requests,
until you remove it or run a prune (see below).
Add and edit patterns
The form next to the list creates a new pattern. Pick a kind, enter the
value, and save. To change a pattern, open it from the list, edit the
fields, and save. The form checks the value before it stores the pattern
and shows a clear message when something is wrong, for example an invalid
IP address or a broken regular expression.
Pattern kinds
A pattern's kind decides what part of the request it compares against.
ip
Blocks one exact client IP address, for example 203.0.113.10.
cidr
Blocks a whole IP range in CIDR notation, for example
203.0.113.0/24.
path_exact
Blocks requests whose path is exactly this value, for example
/old-login.
path_prefix
Blocks requests whose path starts with this value, for example
/.git/.
path_regex
Blocks requests whose path matches this regular expression, for example
#^/(\.git|\.env)#.
header_exact
Blocks requests where a header has exactly this value. Put the header
name in the target field, for example target User-Agent and value
BadBot/1.0.
header_regex
Blocks requests where a header matches this regular expression. Put the
header name in the target field, for example target User-Agent and
value #(sqlmap|nikto)#i.
request_regex
Blocks requests where the regular expression matches a combined string
of the path, the query string, and the request headers, for example
#(union\s+select|<script)#i.
The target field is only used by the two header kinds. For every other kind
you can leave it empty.
Expiry and prune
The expiry date is optional. When set, it must lie in the future. An expired
pattern stops blocking at once, but its row stays in the list so you can see
it. The Prune button deletes all expired patterns in one step.
Integrity check
The view checks the pattern file on every visit. When the file is broken,
for example because it holds invalid data or a pattern with an unknown kind,
a warning banner appears. The firewall silently skips the affected entries
during request handling, so the banner is your signal to open the
patterns file and fix or remove them.
Blocked keys
The Blocked keys view: active bans grouped by the rule that created them.
This view lists the keys that fail2ban and allow2ban rules have
banned automatically. A key is usually a client IP address. The bans are
read live from the store that your configuration uses (see Storage),
so the view is empty when you use the InMemoryCache, which keeps no state
between requests.
Bans are grouped by the rule that created them. Each group carries a badge
that shows the rule type, fail2ban or allow2ban. Inside a group every
ban shows the key, the remaining time, and the exact time the ban ends. The
bans with the least time left are listed first. Use the search field to find
a single key across all groups.
The Unban button removes a single ban after a confirmation
dialog and lets the key through again right away. When the behavior that
triggered the ban continues, the rule bans the key again on the next
matching request.
Blocklist matches do not appear here. A blocklist rule answers each matching
request with a 403 response on the spot and keeps no ban, so there is nothing
to list. To see blocklist activity, use the Event log
and the Statistics view.
Event log
The Event log view: the type tags, the active key filter, and the search field above the event table.
This view lists the latest recorded firewall events, newest first. Every
entry shows the time, the event type, the rule, the key (an anonymized IP
address, or a hash for sensitive keys), an actions column, the request line
with the user agent, and the event details. The request line contains the full request
target including the query string, so GET payloads such as injection
attempts are visible (and searchable) as they arrived.
The details column renders everything the event carried as key: value
lines: the counters of the rule that fired (threshold, count,
banSeconds) and the metadata the matcher attached to its match. For an
OWASP CRS match that is the rule id, its message (msg), the matched
target (owasp_matched_variable, for example
REQUEST_HEADERS:User-Agent) and the value the rule fired on
(owasp_matched_value) - readable, so the match can be understood and
tuned; the matcher redacts credential values (cookies,
Authorization-type headers) before they reach the log. Submitted POST
parameters are not stored; the log records only what led to the match. The
diagnostic headers appear as `diagnosticHeaders.X-Phirewall-Owasp-Rule:
942100`` lines, independently of the ``X-Phirewall-*` response headers, so
you can inspect which rule fired without exposing that information to
clients.
With the eventLogRequestHeaders extension setting enabled, every event
also records the request headers, shown collapsed behind their own details
element in the request column - the full picture of how a request arrived.
Credential headers are stored redacted; see Statistics for the
privacy notes. And while eventLogFullIpRules lists rules whose events
store the client IP unanonymized for an ongoing attack analysis, a warning
icon appears in the view's header - a click shows the affected rules - and
the System > Status report warns as well.
When a client triggers many events, the list collapses them: each key shows
only its three newest events, and the third row carries a hint with the
number of older events. Events without a key, for example blocklist matches,
are never collapsed. The filter button in the actions column - a plus
overlay marks it - filters the list to that key and shows every one of its
events;
in the filtered view it turns into a remove-filter button with a minus
overlay. The hint on a collapsed key opens the same filter. The rule is clickable and filters the list to the events of that
rule; both filters combine with the tags and the search. Every active filter
appears above the list and is removed again with the close button next to
it.
The view covers the last seven days by default; the range buttons in the
header switch between 24 hours, 7 days, 30 days, and the whole log. A
bounded range also keeps the view fast on large event tables.
A lock icon next to a key means the key is blocked right now: an active
fail2ban or allow2ban ban, or a matching ip or cidr entry on the
pattern blocklist. The icon's tooltip names
the source, for example the banning rule. The check works for every banned
key, including hash-only keys; for cidr entries with an anonymized key
it is limited to networks at least as coarse as the anonymization mask
(/24 for IPv4, /64 for IPv6).
Keys that are not blocked yet and store the full IP address offer a red
block button next to the key. After a confirmation dialog it creates
an exact ip entry on the pattern blocklist for exactly the address the
row displays; the entry appears in the Patterns view, where it can be edited,
given an expiry, or removed. This requires the full address, so the button
appears with IP anonymization disabled or for events whose rule is listed
in eventLogFullIpRules. Anonymized addresses are not blockable from the
log - the real client IP behind the anonymized network address is unknown -
and neither are keys stored as hash only (for example header or session
based throttle keys), where the clear text needed for a pattern entry does
not exist.
Single keys can also be hidden from the list: the minus button next to the
key hides all of its events, for example a noisy
monitoring service while inspecting the remaining traffic. Hidden keys
appear as chips above the list and can be removed there one by one; up to
20 keys can be hidden at the same time.
Filter the list by event type with the type tags: a click toggles a tag,
and all active tags combine into one filter. Only event types that actually
occur in the log are offered as tags, plus any filter that is currently
active, so a stored filter can always be toggled off. When the log still
contains entries older than the configured retention period, the view shows
a warning: the firewall:eventlog:prune console command is not running
regularly and should be scheduled (TYPO3 scheduler or cron). The active tags, the search
term, the hidden keys, and the selected time range are stored per backend
user and restored the next time the module is opened; Reset clears them.
The key filter is a transient drill-down and is not stored. The search field matches rule names, keys, and request
paths. It also compares the search term against
the stored key hash, so searching for the full IP address (for example
203.0.113.10) finds its events even when the list only displays the
anonymized form 203.0.113.0. The list is paginated with 50 entries per
page; the pager keeps the active filters. See Statistics for the
retention settings of the underlying log table.
Statistics
The Statistics view: the blocked-requests chart over time and the top lists below it.
This view answers one question: how much unwanted traffic the firewall
blocked. It shows the number of attackers blocked today, a chart over time,
and the rules and paths that triggered most often. For the full description
of the recorded data, the privacy model, and the extension settings, see
Statistics.
Common attacks
Problem-first recipes: what to do when a specific kind of unwanted traffic
hits your site. Each section names the right tool and links to the chapter
with the details.
Tip
If a CDN/WAF (such as Cloudflare) runs in front of your site, filter
there first: it stops unwanted traffic before it reaches the
application. The extension complements that with TYPO3-aware rules, and
is your main line of defence when there is no edge layer.
Form spam is almost always automated, so hardening the form itself beats
chasing the constantly rotating IP addresses. In forms built with the TYPO3
Form Framework, start with the built-in honeypot (and a CAPTCHA where
available); other form extensions ship equivalent protections. Beyond that:
For forms built with the TYPO3 Form Framework, add the
Firewall: flood protection finisher. It reports every
submission to the firewall and bans a client that submits faster than a
configured threshold, catching both bots and real visitors hammering the
form. This is the extension's dedicated answer to form flooding, see
Form flood protection.
A single IP address or network keeps abusing the form: add a pattern of
kind ip or cidr in the backend module,
with an expiresAt a few days out so it cleans itself up.
Cap how often the form can be submitted with a throttle in
config/system/phirewall.php, scoped to the page that holds the
form so it cannot affect the rest of the site:
$config->throttles->add(
name: 'contact-form-flood',
limit: 3,
period: 600,
// Only count POST submissions to the contact page. Without a key// the throttle uses the default client-IP resolver, which applies// TYPO3's reverseProxyIP settings.
scope: static fn(\Psr\Http\Message\ServerRequestInterface $request): bool
=> $request->getMethod() === 'POST'
&& str_starts_with($request->getUri()->getPath(), '/contact'),
);
The recipes below cover frontend logins (felogin or a custom login)
only. The firewall and its aspect run as frontend middlewares, so
brute-force attempts against the backend login (/typo3) never reach
them. TYPO3 rate limits backend logins itself; the FAQ
explains why the backend is not protected and what to do instead.
The firewall runs before TYPO3, so on its own it cannot tell a failed
login from a normal request. Two approaches:
Count login posts. Ban clients that post to the login page again
and again, no code needed: see the allow2ban recipe in
Examples. Simple, but it counts successful and failed logins
alike, so the threshold must stay generous.
Report failed logins. Precise, in two steps. First define the rule
in config/system/phirewall.php:
$config->fail2ban->add(
'login-failures',
threshold: 5,
period: 300,
ban: 3600,
// Failures are reported explicitly, the filter never matches on// its own.
filter: static fn(): bool => false,
);
Copied!
Then report each failed login, for example from a listener on TYPO3's
failed-login event, through the firewall Context aspect:
The firewall aspect is registered automatically in frontend
requests, see Middleware. Only reported failures count, so
legitimate users are never locked out by successful logins.
SQL injection and other request payload attacks
Attacks that hide in the request content (query string, body, headers) need
a rule engine rather than a block list. Install the OWASP Core Rule Set
preset package and pick a paranoia level, see Presets.
A crawler is slowing down the site
The right response depends on which crawler it is; the User-Agent
header in your access log tells you.
Search engines and AI search bots (Googlebot, Bingbot, OpenAI's
OAI-SearchBot, Anthropic's Claude-SearchBot) should generally
not be blocked: they are how people find and get referred to your
site. To ease the load instead: Bing and Yandex honour a Crawl-delay
in robots.txt; Googlebot ignores it, but treats repeated
429/503 responses as an overload signal and temporarily lowers
its crawl rate, so a throttle that answers with 429 is a valid way
to slow it down.
AI training crawlers (GPTBot, ClaudeBot, CCBot) honour
robots.txt, which is the appropriate place to opt out:
Blocking these controls whether your content is used for AI training;
it does not affect whether AI tools can find or cite your site.
SEO crawlers (AhrefsBot, SemrushBot, MJ12bot, DotBot) can be rate
limited or blocked with the bot control preset, see Presets, or
opted out via robots.txt.
Note
Blocking by User-Agent only works for crawlers that identify
themselves honestly. Stealth crawlers that
spoof a browser User-Agent
need behaviour-based rules (throttles, fail2ban) or edge defences.
Traffic from specific countries
Geo-blocking is best handled at the edge (CDN/WAF). Inside TYPO3 there is
no reliable country signal, hand-maintained per-country IP ranges go stale
fast, and even done well it is blunt: it blocks real visitors and VPN
users while attackers switch countries. Filtering on behaviour rather than
origin (scanner paths, throttles, fail2ban) catches malicious traffic
regardless of where it comes from. If geo-blocking is a hard compliance
requirement, it belongs at the hosting or CDN layer.
Which rule blocked a visitor?
Open the backend module: Blocked keys lists the active
fail2ban/allow2ban bans grouped by rule, Patterns the static
blocks. Remove the matching entry to unblock the visitor immediately. The
event log shows which rule matched historically.
On development or staging systems, diagnostic response headers name the
matching rule on every blocked response:
$config->enableResponseHeaders();
$config->enableOwaspDiagnosticsHeader(); // adds the OWASP rule ID
Copied!
A blocked response then carries X-Phirewall (the block type) and
X-Phirewall-Matched (the rule name).
Warning
Enable diagnostic headers only in development or staging. In
production they reveal your rule set to attackers.
The file returns a closure. The closure receives the TYPO3 event dispatcher
and returns a configured Flowd\Phirewall\Config object:
<?phpuseFlowd\Phirewall\Config;
useFlowd\Phirewall\Store\PdoCache;
usePsr\EventDispatcher\EventDispatcherInterface;
useTYPO3\CMS\Core\Database\ConnectionPool;
useTYPO3\CMS\Core\Utility\GeneralUtility;
returnfunction(EventDispatcherInterface $eventDispatcher): Config{
// 1. The store keeps counters for rate limiting and bans. See the Storage page.
$cache = new PdoCache(GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('phirewall_cache')->getNativeConnection());
$config = new Config($cache, $eventDispatcher);
// 2. Add your rules here.
$config->blocklists->add(
name: 'block-env-probes',
callback: fn($request) => str_starts_with(strtolower($request->getUri()->getPath()), '/.env')
);
return $config;
};
Copied!
The closure receives the TYPO3 event dispatcher. Pass it to the Config
object as shown above; the effective configuration always uses the TYPO3
event dispatcher, so event logging and the Statistics view work even
when your file does not pass it on.
All rule types (safelists, blocklists, throttles, fail2ban, allow2ban,
tracks) and their options are documented in the
phirewall documentation. They work exactly the
same way inside this file. See Examples for TYPO3 recipes.
What the extension adds automatically
The extension builds its defaults first and merges your configuration file
on top. Your file wins on every name clash, so it can override each default
by using its name.
Client IP resolver
When your configuration does not call $config->setIpResolver(), the
extension sets a resolver that reads the request's normalized parameters
(NormalizedParams). This applies TYPO3's reverseProxyIP settings,
so rules see the real visitor address behind a reverse proxy or CDN. When no address can be resolved, the resolver
returns null and rules that key on the client IP skip the request.
Details: Trusted proxies.
Backend managed block patterns
The block patterns from the backend module are
added first as the blocklist rule typo3-blocklist, and they stay
active even when your configuration file is missing. A rule with the
same name in your file replaces them, so only define a rule named
typo3-blocklist when you want to take over the backend managed
patterns yourself. The patterns live in
config/system/phirewall.patterns.json next to phirewall.php;
point the extension configuration setting patternsDirectory at
another directory when that location is read-only at runtime. The
file's lock file is created in the same directory. The directory must
lie within the TYPO3 project directory or within
$GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath']; other values
are ignored with a logged warning and the default directory is used.
Compiled-data cache
Preset packages such as OWASP CRS and the bad-IP list parse large data
sources when a rule first evaluates. Under PHP-FPM that parsing would run
on every request. The extension gives the Config a compiled-data
cache so the parsed data is served from OPcache-backed artifacts and
re-parsed only when a source file changes. It is on by default and writes
to var/cache/code/firewall (outside the web root). Turn it off or point
it at another directory in the extension configuration
(compiledCacheEnabled, compiledCacheDirectory). The directory must
lie within the TYPO3 project directory or within
$GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath']; other values are
ignored with a logged warning and the default directory is used. If the
directory cannot be created the extension logs a warning; a directory
that exists but is not writable degrades silently. Either way the presets fall back to
per-request parsing, so the firewall keeps working.
Behavior without a configuration file
When the file is missing, the extension falls back to a default
configuration. When the file exists but is broken, the extension logs the
problem and uses the same fallback: a warning when the file does not return
a closure or the closure does not return a Config object, an error when
loading the file fails, for example with a syntax error or an exception:
Store: InMemoryCache (nothing persists between requests)
Rules: only the backend managed block patterns
The website keeps working. Note that rate limiting and bans need a real
store, so create the configuration file for any protection beyond static
block patterns.
Examples
This page collects ready-to-use recipes for common tasks. Each one is a
complete config/system/phirewall.php file and returns the closure
described in Configuration.
All examples use the ApcuCache store, the first choice on a single
server. Pick the store that fits your setup on the Storage page.
Rate limiting and bans need a store that keeps state between requests, so
they do not work with the InMemoryCache.
Safelist office and monitoring IPs
Let trusted clients through before any other rule runs, for example your
office network, an uptime monitor, or a load test runner. A safelist match
ends the check at once, so these clients are never rate limited or banned.
Ban a client that posts to the frontend login again and again. An allow2ban
rule with a filter counts the requests that match the filter and lets them
through, then bans the client once it crosses the threshold within the period.
A fail2ban rule is the wrong tool here: it treats every match as malicious and
answers each login post with a 403, which locks out real users. Replace
/login with the path of the page that holds your felogin form.
This bans a client for 15 minutes after 5 login posts within 5 minutes.
Ban request floods with allow2ban
An allow2ban rule counts every request from a client, not only the ones that
match a filter, and bans the client once it crosses the threshold in the
period. Use it as a blunt guard against request floods. Keep the threshold
well above what a normal visitor reaches, so real people are never caught.
This bans a client for 10 minutes once it sends more than 240 requests in 60
seconds.
Throttle a search or JSON endpoint
Limit how often a client may call an expensive endpoint, for example a site
search or a JSON API. A throttle allows a fixed number of requests per period
and answers further requests with a 429 response and a Retry-After
header. The scope keeps the counter to the endpoint you name, so browsing the
rest of the site does not add to it.
enableRateLimitHeaders() adds the X-RateLimit-* headers so clients can
see how much of their budget is left.
Combine a preset with your own rules
Apply a ready-made preset and add your own rules on top. with() returns a
new configuration, so assign it back to $config. Rules you add afterwards
run alongside the preset. See Presets for the available packages.
Replace the default 403 body with your own message and headers. The closure
receives the rule name, the rule type, and the request, and returns a PSR-7
response. Keep the 403 status so crawlers and caches treat the request as
blocked.
<?phpuseFlowd\Phirewall\Config;
useFlowd\Phirewall\Config\Response\ClosureBlocklistedResponseFactory;
useFlowd\Phirewall\Store\ApcuCache;
usePsr\EventDispatcher\EventDispatcherInterface;
useTYPO3\CMS\Core\Http\ResponseFactory;
useTYPO3\CMS\Core\Http\StreamFactory;
returnfunction(EventDispatcherInterface $eventDispatcher): Config{
$cache = new ApcuCache();
$config = new Config($cache, $eventDispatcher);
$config->blocklists->add(
name: 'block-env-probes',
callback: fn($request) => str_starts_with(strtolower($request->getUri()->getPath()), '/.env'),
);
$config->blocklistedResponseFactory = new ClosureBlocklistedResponseFactory(
fn(string $rule, string $type, $request) => (new ResponseFactory())
->createResponse(403)
->withHeader('Content-Type', 'text/plain; charset=utf-8')
->withBody((new StreamFactory())->createStream('Blocked by the firewall.')),
);
return $config;
};
Copied!
Lock the site down temporarily
Close the site to everyone except a few addresses, for example during
maintenance. The safelist is checked before the blocklist, so listed clients
pass while the catch-all blocklist answers every other request with a 403.
Remove both rules when you are done.
The extension records events in its own log (see Statistics). To also
send them to the TYPO3 logging framework, register a PSR-14 listener for the
phirewall events. This is a listener class in your own extension or site
package, not part of the phirewall.php file.
TYPO3 reads the event to listen for from the type of the __invoke
argument. On TYPO3 13 you can use the #[AsEventListener] attribute instead
of the tag. The other events live in the Flowd\Phirewall\Events namespace,
for example ThrottleExceeded and Fail2BanBanned.
FAQ
Short answers to questions that come up when running the firewall in TYPO3.
For questions about the firewall engine itself (rule evaluation, stores,
advanced features) see the
phirewall FAQ.
Why is the TYPO3 backend not protected?
The firewall runs as a frontend middleware. It covers the TYPO3 frontend
only, not /typo3, the install tool, or files that the web server delivers
directly (see Middleware). Protect the backend at the web server or
network level, for example with an IP allow list for /typo3. TYPO3 also
brings its own rate limiting for backend login attempts.
How does the firewall see the real client IP behind a proxy?
The extension resolves the client IP through the request's normalized
parameters (NormalizedParams), which apply the reverseProxyIP
settings of your TYPO3 installation. Configure those
settings once and both TYPO3 and the firewall see the real visitor address
(see Trusted proxies).
Can I use the TYPO3 caching framework as a store?
No. The store must implement PSR-16 and offer atomic counters for rate
limiting and bans. The TYPO3 caching framework does neither, so counters
would be lost or wrong. Use one of the stores in Storage, for
example ApcuCache on a single server.
Should I commit phirewall.patterns.json?
Usually not. The file holds the block patterns that editors manage in the
backend module at runtime, so it is data, not code. When you deploy the file
from Git, a deployment overwrites the changes made on the live site. Exclude
it from deployment (for example through .gitignore) unless you never
touch the patterns in the backend and manage them only in the file.
What happens if the configuration file has an error?
The extension falls back to the default configuration: the InMemoryCache
store and only the backend block patterns. The website keeps working. A file
that does not return a closure, or whose closure does not return a Config
object, logs a warning. A file that fails, for example with a syntax error or
an exception, logs an error. Check the TYPO3 log after changing the file, and
test changes on a staging system first.
Why is the blocked keys view empty?
The view lists the bans that fail2ban and allow2ban rules created and
that are still active. It is empty when you use the InMemoryCache, which
keeps no state between requests, when your configuration has no fail2ban or
allow2ban rules, or when no ban is active right now. When the
InMemoryCache is active, the view shows a warning, and the firewall
logs one when counter rules are registered on it. Blocklist matches never
appear here, because they answer each request with a 403 and keep no ban.
Why is the statistics view empty?
Most often event logging is switched off. When eventLogEnabled is off the
view shows a hint and stays empty. Otherwise there may be no events yet in the
selected time range, or the event types you look for are not in the
eventLogTypes setting (see Statistics).
Does the extension work without Composer?
Yes. Install the package from the TYPO3 Extension Repository. The TER package
bundles the phirewall library, the three preset packages, and
psr/simple-cache, so nothing else is needed (see Installation).
What does the firewall cost per request?
Little. The middleware runs early, before TYPO3 resolves the site or the
page, so a blocked request is answered at once and never reaches the CMS. For
an allowed request the cost is evaluating your rules. Counter rules (throttle,
fail2ban, allow2ban, track) each do one store lookup, so a fast store keeps
the overhead low on busy sites. Event logging adds one database insert per
recorded event, not per request, and the high-volume event types are off by
default.
How do I disable the firewall in an emergency?
Rename or empty the configuration file. The extension then falls back to the
default configuration, and only the backend block patterns stay active. To
drop those too, remove the patterns in the backend module. Inside the file
you can also call $config->disable() to let every request pass without
any check.
What if I locked myself out?
The firewall never runs in the backend, so a rule can block your frontend
access but never /typo3. Open the backend module and remove the pattern
in the Patterns view, or lift the ban in the
Blocked keys view. When a rule in the configuration file is the
cause, edit or rename that file (see Backend module).
What about the event log and GDPR?
The event log is built to hold as little personal data as possible. The
client key, usually the IP address, is stored only as a keyed hash
(HMAC-SHA-256). A readable address is kept only for real IP addresses and,
by default, only in shortened form. Entries are deleted after the retention
period. The log also stores the request path, method, host, and user agent.
Two opt-in settings extend what is recorded and deserve a privacy review of
their own: eventLogFullIpRules stores unanonymized IPs for listed rules
during an attack analysis, and eventLogRequestHeaders records the
request headers (credential headers redacted). Review this against your
privacy policy, keep IP anonymization on when you do not need full
addresses, and set a retention that fits your needs (see Statistics).
Why are bans gone after the upgrade to 0.4?
Version 0.4 updates the firewall engine from phirewall 0.3 to 0.8. Along the
way the engine changed its internal cache key format. Active bans and running
counters are forgotten once when you deploy the upgrade, then rebuild with the
next matching requests. This reset
happens only once (see Installation).
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-flood with 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/system/phirewall.php 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,
);
Copied!
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/system/phirewall.php (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,
);
Copied!
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\Typo3Firewall\Event\FloodProtectionFinisherTriggered
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:
Register the class as an event listener in the Services.yaml of
your site package. The rule it points to must be defined in
config/system/phirewall.php.
Installation
Requirements
Extension version
0.9
TYPO3
12.4 LTS, 13.4 LTS, 14
PHP
8.3, 8.4, 8.5
Firewall engine
flowd/phirewall 0.10
The firewall works with every database supported by TYPO3. Rate limiting and
bans additionally need one of the stores described in Storage.
Installation with Composer
composer require flowd/typo3-firewall
Copied!
Then activate the extension:
vendor/bin/typo3 extension:setup
Copied!
The frontend middleware is registered automatically. Continue with
Quick start to create your first configuration file.
Optional packages
Three preset packages add ready-made protection rules (see Presets):
With the TYPO3 reports module installed, the firewall adds two checks to
System > Status: a PCRE JIT check that warns when PCRE JIT is
disabled or unavailable (the firewall evaluates regular expression patterns
on every request, so matching would fall back to the slower interpreter),
and a privacy check that warns while the eventLogFullIpRules exception
stores unanonymized client IPs (see Statistics).
composer require typo3/cms-reports
Copied!
Installation without Composer (TER)
Install the extension from the
TYPO3 Extension Repository
using the extension manager, then activate it.
The TER package bundles everything the firewall needs: the phirewall library,
the three preset packages, and psr/simple-cache. They live inside the
extension under Resources/Private/Php/ComposerLibraries and are loaded
automatically. No extra installation step is needed, and the presets are
available without further setup.
Upgrade from 0.8
Version 0.9 extends the event log and fixes the client IP resolution.
Review these points when upgrading:
Database schema and caches
Update the database schema (a new index on tx_firewall_event) and
flush all caches after the upgrade, for example with
vendor/bin/typo3 extension:setup followed by
vendor/bin/typo3 cache:flush.
The event log view defaults to the last 7 days
Older entries stay recorded and reachable through the new "All" time
range button.
The firewall middleware moved after the normalized params
The middleware now runs after typo3/cms-core/normalized-params-attribute
(and before site resolution), so the reverseProxyIP settings apply
to every IP-keyed rule. Review site packages that order their own
middlewares relative to the firewall.
New opt-in event log settings
eventLogFullIpRules and eventLogRequestHeaders record more data
for attack analysis and are off by default; see Statistics before
enabling them.
Upgrade from 0.7
Version 0.8 changes what the event log records. Review these points when
upgrading:
POST parameters are no longer stored
Event log entries record the metadata of the match itself (rule,
counters, matched target and value) instead of the submitted POST
parameters. The eventLogMaskParameters extension setting was removed
together with the parameter storage; a leftover value in the extension
configuration is ignored.
The track_hit event type is deprecated
Track events are recorded as track_matched (every hit of a track
rule, high volume) or track_threshold_reached (a track rule with a
limit reached it). Replace track_hit in the eventLogTypes
extension setting with one or both of the new types; until then the
deprecated value keeps enabling both and logs a deprecation.
New default event log types
The default eventLogTypes now include track_threshold_reached.
Installations without an explicit type list start recording an entry
when a track rule with a limit reaches it.
Upgrade from 0.3
Version 0.4 updates the firewall engine from phirewall 0.3 to 0.8. Review
these points when upgrading:
New database table
Version 0.4 records firewall events in the new table
tx_firewall_event. Update the database schema after the upgrade,
for example with vendor/bin/typo3 extension:setup.
Counters and bans reset once
phirewall 0.5 changed its internal cache key format. Active bans and
running rate limit counters are forgotten one time when you deploy the
upgrade. They rebuild automatically with the next matching requests.
Bans trigger at the threshold
A fail2ban or allow2ban rule now bans when the threshold is reached, not
one request later. With threshold: 5 the ban starts at the fifth
matching request. Lower your thresholds by one if you relied on the old
behavior.
Fail2Ban blocks every matching request
A fail2ban rule answers every request its filter matches with a
403, not only the request that reaches the threshold; the threshold
controls when the client is banned outright. If a rule in your
phirewall.php filters on something a legitimate request can carry
(for example every POST to a login path), move it to an allow2ban rule
with the same filter, which counts the matches but lets them pass until
the threshold. Rules that match only clearly malicious traffic (scanner
paths) block the probe on sight. Rules driven by
RequestContext::recordFailure() (an empty filter) are unaffected.
New event type fail2ban_matched
A blocked-but-not-yet-banned fail2ban match is recorded as the new event
type fail2ban_matched and counts towards the blocking statistics. It
is enabled by default; adjust the logged types in the extension
configuration if you do not want it.
$config->blocklists->owasp() was removed
The OWASP rule engine moved into the package
flowd/phirewall-preset-owasp-crs. See Presets for the new way
to enable it.
$config->safelists->trustedBots() was removed
Wire the matcher directly instead:
$config->safelists->addRule(new \Flowd\Phirewall\Config\Rule\SafelistRule(
'trusted-bots',
new \Flowd\Phirewall\Matchers\TrustedBotMatcher(cache: $cache)
));
Copied!
KeyExtractors::ip() is deprecated
Leave out the key argument of throttle, fail2ban, allow2ban, and
track rules. They then count per client IP resolved through TYPO3
(see Trusted proxies).
Introduction
What does the extension do?
The Firewall extension adds a web application firewall to your TYPO3 website.
It inspects every frontend request before TYPO3 processes it and can:
Block requests from specific IP addresses or IP ranges
Block requests for suspicious paths, headers, or patterns
Limit how often a client can call certain pages (rate limiting)
Ban clients temporarily after repeated abuse (like Fail2Ban)
Record firewall events and show statistics in the backend
Administrators manage static block patterns directly in the
TYPO3 backend module. Changes take effect immediately, without a deployment.
Relation to phirewall
The firewall engine is the open-source package
flowd/phirewall. The extension wires
it into TYPO3: it registers the request middleware, loads your configuration
file, resolves the client IP through TYPO3, and adds the backend module
and the event log.
This documentation covers everything TYPO3-specific. All engine features
(rule types, stores, advanced options) are documented at
https://phirewall.de/ and are used exactly the same way inside TYPO3.
Where things live
Firewall configuration: config/system/phirewall.php (see Configuration)
Backend managed block patterns: config/system/phirewall.patterns.json, directory configurable (see Backend module)
Recorded firewall events: database table tx_firewall_event (see Statistics)
Middleware
The extension registers the firewall as a PSR-15 middleware in the TYPO3
frontend request stack.
Position in the request stack
The middleware runs early: after typo3/cms-core/normalized-params-attribute
and before typo3/cms-frontend/site. Two consequences follow from this
position:
Blocked requests are cheap. The firewall answers before TYPO3 resolves
the site, the page, or any content.
The firewall sees the request with TYPO3's normalized parameters already
attached, so the client IP respects the trusted-proxy settings
(see Trusted proxies), while site handling has not run yet.
What is protected, and what is not
The middleware covers every request that reaches the TYPO3 frontend,
including page requests, frontend login forms, and frontend APIs.
Not covered:
The TYPO3 backend (/typo3) and its login
The install tool (/typo3/install.php)
Files that the web server delivers directly, for example everything under
fileadmin or _assets
Protect these entry points at the web server or network level, for example
with IP allow lists for /typo3. TYPO3 itself brings rate limiting for
backend login attempts.
Warning
If you register the firewall middleware in the backend stack yourself,
a rule that matches too much can lock you out of the backend, including
the module you would use to remove the ban. Test rules in the frontend
first.
Disable the firewall temporarily
Return a configuration without rules, or rename the configuration file. The
extension then falls back to the default configuration, and only the block
patterns from the backend module stay active. To
disable those too, remove the patterns in the backend module.
Read the firewall decision from PHP code
A second middleware flowd/typo3-firewall-aspect exposes the firewall
decision through the TYPO3 Context API as the firewall aspect. Like the
firewall itself it runs in the frontend stack only, so the aspect is
available in frontend requests and not in the backend. Application code can
read the decision through the aspect:
useTYPO3\CMS\Core\Context\Context;
useTYPO3\CMS\Core\Utility\GeneralUtility;
$firewallAspect = GeneralUtility::makeInstance(Context::class)->getAspect('firewall');
// The FirewallResult of the current request:
$firewallResult = $firewallAspect->get('result');
// Report an application-level failure, for example a failed login,// to a fail2ban rule defined in phirewall.php:
$firewallAspect->recordFailure('login-failures');
// Report a hit to an allow2ban rule, for example an expensive// operation the firewall cannot see from the request alone:
$firewallAspect->recordHit('expensive-operation');
Copied!
recordFailure() and recordHit() count against the client IP by
default; the firewall resolves it with your trusted-proxy settings after
the handler has finished. Pass a key as second argument only when the rule
should count something the firewall cannot derive from the request itself.
Signals reported to a rule name that is not configured are ignored, so
calling code does not need to check the configuration first.
The extension ships a phpstan configuration that
maps getAspect('firewall') to the
FirewallAspect
class. Projects
using phpstan/extension-installer pick it up automatically.
Note
The aspect is only registered when the firewall middleware has run for
the current request. Otherwise getAspect('firewall') throws an
AspectNotFoundException.
If you do not want the aspect registered at all, disable the middleware in
the Configuration/RequestMiddlewares.php of your site package:
Presets are ready-made rule bundles. You apply them to your configuration
with $config = $config->with(...), one line per preset. Note the
assignment: with() returns the combined configuration instead of
changing $config in place.
Three preset packages are available. In a Composer-based installation,
install the ones you want (see Installation); the TER package already
bundles all three.
OWASP Core Rule Set
The package flowd/phirewall-preset-owasp-crs detects common attack
patterns like SQL injection, cross-site scripting, and path traversal,
based on the OWASP Core Rule Set:
Start with paranoia level 1. Higher levels detect more, but also produce
more false positives. The fail2ban variant blocks each matching request just
like the blocklist, but additionally bans a client key that keeps matching,
so a repeat offender is locked out for the whole ban period:
The rule set also covers requests for hundreds of sensitive files such as
.env, .git, or .htpasswd, so you do not need rules of your own
for those probes.
Bot control
The package flowd/phirewall-preset-bots controls crawlers by their
User-Agent:
Bots constantly probe paths of other CMS products, for example
/wp-admin or /xmlrpc.php. The OWASP rule set does not block these
paths, because they are legitimate on a WordPress site. On a TYPO3 site they
never are, so a single custom rule handles them:
Every preset rule has a namespaced name, for example preset.bots.*. A
rule that you define later under the same name replaces the preset rule, so
you can adjust single rules without giving up the rest of a preset.
Quick start
Follow these steps to get a working firewall in a Composer-based TYPO3
project.
1. Install the extension
composer require flowd/typo3-firewall
Copied!
The frontend middleware is registered automatically. Without a configuration
file the firewall only enforces the block patterns managed in the backend
module.
2. Create the configuration file
Create the file config/system/phirewall.php. This minimal example blocks
requests for paths that only scanners ask for:
The PdoCache store creates its phirewall_cache table on its own the
first time it runs. You must also declare the table in the
ext_tables.sql of your site package, otherwise TYPO3 treats it as
unused; Storage shows the definition and other store options.
Important
PdoCache needs a database connection with a PDO driver such as
pdo_mysql. With the mysqli driver it does not work. Check the
driver entry in config/system/settings.php; Storage
explains the options.
The extension resolves the client IP for you through TYPO3, so the firewall
sees the real visitor address behind a reverse proxy or CDN
(see Trusted proxies).
3. Verify it works
Request a blocked path. The firewall answers with status 403:
The extension records what the firewall does and shows it in the
Statistics view of the backend module.
This lets you see how much unwanted traffic your website receives and which
rules and paths are hit most.
The event log
Every firewall action is written as one row to the database table
tx_firewall_event. A row holds the event type, the rule name, the ban
type for ban events, the client key (see the privacy section below), the
request host, path, and method, the user agent, rule numbers such as the
threshold and the counter, for errors the exception class and message, and
the time. It never stores a page, a session, or content. The recorded event
types are:
blocklist_matched
A blocklist rule answered a request with a 403 response.
throttle_exceeded
A client sent more requests than a rate limit allows.
fail2ban_matched
A fail2ban rule blocked a request that matched its filter, before the
ban threshold was reached.
fail2ban_banned
A fail2ban rule banned a client after repeated abuse.
fail2ban_blocked
A fail2ban rule blocked a request from a client that is already banned.
High volume, so off by default.
allow2ban_banned
An allow2ban rule banned a client for too many requests.
allow2ban_blocked
An allow2ban rule blocked a request from a client that is already banned.
High volume, so off by default.
safelist_matched
A safelist rule let a request through without further checks.
track_matched
A track rule counted a request without blocking it. High volume, so off
by default.
track_threshold_reached
A track rule with a limit reached it: the counted requests within the
period hit the configured threshold. The rule still does not block; the
entry is the signal to look at the tracked traffic.
track_hit
Deprecated: split into track_matched and track_threshold_reached.
A configured track_hit enables both and logs a deprecation; new
entries are never written under the old type.
firewall_error
The firewall hit an internal error, for example when the store was
unreachable.
The blocklist_matched, throttle_exceeded, fail2ban_matched,
fail2ban_banned, fail2ban_blocked, allow2ban_banned, and
allow2ban_blocked types count as a blocked attacker: each one rejected a
request. They feed the numbers, the chart, and the top lists in the statistics
view. The firewall_error type is recorded but not counted, because an
internal error makes the firewall fail open by default, so the request was not
blocked. Four types are high volume and switched off by default so they do not
fill the table quickly: safelist_matched and track_matched fire on normal
traffic, and fail2ban_blocked and allow2ban_blocked fire on every
request from an already-banned client.
Settings
The extension configuration controls what is logged and for how long. Open
it under Admin Tools > Settings >
Extension Configuration and select firewall.
eventLogEnabled (default: on)
Turns the event log on or off. When off, nothing is recorded and the
statistics view stays empty.
A comma-separated list of the event types to record. Add the high-volume
types (fail2ban_blocked, allow2ban_blocked, safelist_matched,
track_matched) only when you need them, and expect many more rows.
eventLogRetentionDays (default: 30)
How many days to keep entries. The prune command uses this value.
eventLogAnonymizeIp (default: on)
Stores client IP addresses in shortened form. The last part of the
address is dropped, so a single visitor can no longer be identified.
eventLogFullIpRules (default: empty)
Comma-separated rule names whose events store the client IP
unanonymized, as a targeted exception from eventLogAnonymizeIp
while a specific attack is analyzed. Restricting the exception to the
rules under investigation and removing it afterwards keeps the data
minimization intact that the anonymization default provides; network
and information security is a recognized legitimate interest (GDPR
recital 49), and the operator should record the analysis in the
processing documentation. While the list is not empty, the event log
view shows a warning icon in its header and the System > Status
report warns, so the exception is not forgotten.
eventLogRequestHeaders (default: off)
Stores the request headers with every event, shown as their own block
in the event details. The headers are read from the raw server
environment (the HTTP_* server params) as PHP received them, so
they show the request as it arrived even when TYPO3 or a middleware
modified the PSR-7 request afterwards; note that the web server and
SAPI already merge duplicate header lines into one comma-separated
value before PHP sees them. Credential headers (Cookie,
Authorization, Proxy-Authorization, X-Api-Key,
X-Auth-Token) are redacted before storing; the remaining headers
can still contain personal data, for example client IPs in forwarding
headers. Enable it only while analyzing an attack and disable it
afterwards.
Privacy and retention
The event log is built to hold as little personal data as possible.
The key of a client, usually its IP address, is stored only as a keyed
hash (HMAC-SHA-256 with the installation's encryption key). The hash lets
the view count distinct clients and find a key by its full value, and the
keying prevents reversing the small IPv4 address space by brute force.
A readable address is kept in a separate field for the backend view, but
only for real IP addresses and, with eventLogAnonymizeIp on, only in
shortened form. Keys that are not IP addresses are never shown in readable
form.
Submitted POST parameters are not stored. An event records only the
metadata of the match itself (rule, counters, matched target and value);
matchers redact credential values before they reach the log.
Entries are deleted after the retention period. The console command
removes the old rows:
vendor/bin/typo3 firewall:eventlog:prune
Copied!
The command deletes entries older than the configured retention. Pass
--days to override it once, for example --days 7. Register the
command as a scheduler task or a cron job so old entries are removed
regularly.
How to read the statistics view
When event logging is off, the view shows a hint and stays empty. Otherwise
it shows:
Two large numbers at the top: Attackers blocked today, the count of
distinct clients blocked since midnight, and Blocked requests, the
total for the selected time range.
A time range switch with three options: the last 24 hours, 7 days, or 30
days. The 24-hour range groups the data by hour, the other two by day.
The selected range is stored per backend user and restored the next time
the view is opened.
A Blocked requests over time chart. Each bar is stacked and split by
event type, so you see at a glance whether blocklists, rate limits, or bans
caused the traffic. Every type keeps the same color across ranges, and a
legend below the chart names each color with its count.
A Recent blocked requests table with the most recent blocking events in
the selected range (up to 20 rows). Each row shows the time, the event type
in the same color as the chart, the rule that fired, the request method and
path, and the client. This answers which rule blocked a specific request. A
client that triggers many events is collapsed to its three newest ones; a
hint shows how many more it caused. The client links to the event log
filtered to that key, where every one of its events is listed.
A Top rules list with the five rules that blocked the most requests,
and a Top blocked paths list with the five paths that attackers
targeted most.
An Events by type list with the count per event type in the range.
Dashboard widgets
The extension ships two widgets for the TYPO3 dashboard. They need the
typo3/cms-dashboard package (see Installation) and read from the
same event log.
Firewall: Blocked today
A single number: the distinct attackers blocked since midnight.
Firewall: Blocked requests
A bar chart of the blocked requests per day over the last seven days.
Statistics, blocked keys, and patterns
The backend module shows firewall data in three ways. It helps to keep them
apart:
Statistics is the history. It tells you what happened over time, even
for events that are long over.
Blocked keys is the present. It lists the bans that are active right
now and lets you lift them (see Backend module).
Patterns are the static rules you manage by hand. They do not depend on
past traffic (see Backend module).
Storage
Rate limiting and bans need a store that persists counters between requests.
The store is the first argument of the Config object in your
configuration file (see Configuration).
Which store should I use?
ApcuCache
First choice on a single server. Needs the APCu extension.
RedisCache
First choice for multi-server setups. Needs a Redis server.
PdoCache
Works without extra services, but opens a database
connection for every request. Fallback only.
InMemoryCache
Testing only. Nothing persists between requests.
Prefer ApcuCache or RedisCache. The firewall runs before TYPO3
boots, and with these stores a blocked request is answered without touching
the database at all. PdoCache opens a database connection for every
request, including the ones the firewall blocks, so an attack still creates
load on the database, which is exactly what the firewall should prevent.
The TYPO3 caching framework cannot be used as a store: it does not implement
PSR-16 and does not offer the atomic counters the firewall needs.
ApcuCache: single-server setups
useFlowd\Phirewall\Store\ApcuCache;
$cache = new ApcuCache();
Copied!
APCu keeps counters in the memory of the PHP process manager. This is the
fastest option, but the counters are per server: do not use it behind a load
balancer, and note that a PHP restart clears all counters and bans.
RedisCache: multi-server setups
useFlowd\Phirewall\Store\RedisCache;
usePredis\Client;
$cache = new RedisCache(new Client('redis://localhost:6379'));
Copied!
All servers share the same counters and bans. Requires the
predis/predis package:
composer require predis/predis
Copied!
Note
The TER package does not bundle predis/predis. In a classic
installation you can still use RedisCache when you install Predis
yourself and take care of its autoloading. Otherwise use ApcuCache
on a single server or PdoCache for multi-server setups.
PdoCache: the TYPO3 database
PdoCache stores its counters in a table of the TYPO3 database, using
the connection settings of your installation, and creates that table on its
own. It needs no additional service, which makes it the fallback when
neither APCu nor Redis is available. Keep the performance cost from above
in mind: every request opens a database connection before the firewall can
block it.
useFlowd\Phirewall\Store\PdoCache;
useTYPO3\CMS\Core\Database\ConnectionPool;
useTYPO3\CMS\Core\Utility\GeneralUtility;
$cache = new PdoCache(GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('phirewall_cache')->getNativeConnection());
Copied!
Warning
PdoCache needs a PDO object, so the TYPO3 database connection
must use a PDO driver such as pdo_mysql. With the mysqli driver,
getNativeConnection() returns a mysqli object and the firewall
configuration fails.
Check the driver entry of your connection in
config/system/settings.php. Either switch it to pdo_mysql, or
keep it and map the firewall table to a separate connection with a PDO
driver:
TYPO3 does not know this table, so the database analyzer in the install tool
treats it as unused and offers to remove it, and with it all counters and
bans. You must declare the table in the ext_tables.sql of your site
package so TYPO3 knows it:
useFlowd\Phirewall\Store\InMemoryCache;
$cache = new InMemoryCache();
Copied!
Counters live only for the current request. Block rules work, but rate
limiting and bans do not, and the blocked keys view in the
backend module always stays empty. Use it for local
experiments or setups that only need static block rules.
Trusted proxies
Why this matters
Rules that work with the client IP (IP blocklists, rate limiting, bans) need
the real visitor address. Behind a reverse proxy, a load balancer, or a CDN,
the connecting address is the proxy, not the visitor. Without correct
resolution, two things go wrong:
Every visitor appears as the same proxy IP. One ban then blocks everyone.
An attacker is not banned, because the counted address is the proxy.
The default: TYPO3 resolves the client IP
The extension resolves the client IP through the request's normalized
parameters (NormalizedParams). This applies the reverse proxy settings
of your TYPO3 installation. Configure them once in
config/system/settings.php (classic installation:
typo3conf/system/settings.php) and both TYPO3 and the firewall see the
real visitor address:
// config/system/settings.php'SYS' => [
'reverseProxyIP' => '203.0.113.10', // the address of your proxy'reverseProxyHeaderMultiValue' => 'last',
],
Without a proxy in front of your website no configuration is needed: the
connecting address is already the visitor.
When no address can be resolved, the resolver returns null and rules
that key on the client IP skip the request.
Using a different resolver
Call $config->setIpResolver() in your configuration file to override the
default, for example to use the phirewall TrustedProxyResolver with its
own trust list:
When the request is blocked (status 403), the firewall sees your real
address. When it passes, the proxy configuration is not applied: check the
reverseProxyIP value. Remove the rule after the test.
Reference to the headline
Copy and freely share the link
This link target has no permanent anchor assigned.The link below can be used, but is prone to change if the page gets moved.