Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Firewall Symfony Laravel Package

kanopi/firewall-symfony

Symfony integration for Kanopi Firewall that adds configurable request firewalls and access rules, letting you allow or deny traffic by IP, network, or custom criteria. Protect routes and enforce access policies directly from Symfony configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. There is no Laravel service provider, no vendor:publish, and no php artisan command. If you are working in a Laravel app, treat this as a reference implementation for the underlying kanopi/firewall library rather than something you can drop into composer.json and expect to work. If you are working in a Symfony app—or maintaining one alongside Laravel services—this is the package you want for path/IP/ASN/rate-limit rules and ALTCHA challenges.

Minimum steps:

  1. Confirm the host app meets the new floor: PHP 8.1–8.5, Symfony 6.4 / 7.4 / 8.1.
  2. Install or upgrade:
    composer require kanopi/firewall-symfony:^1.3
    
    This pulls kanopi/firewall ^2.36, up from ^2.33. The library bump is not optional; several fixes in this release only arrive with the new floor.
  3. Register the bundle in config/bundles.php if it is not already registered, then add the bundle configuration. Use bin/console config:dump-reference and the README for the exact config key/path for your version.
  4. Run the bundle’s doctor and check commands before writing rules:
    bin/console list kanopi:firewall
    bin/console kanopi:firewall:check /
    
  5. First real use case: put a challenge in front of a noisy endpoint such as /wp-login.php, or a rate limit on an API route. Run the bundle in mode: exception so it writes every firewall response itself, and set blocked_response: http_exception if you want blocked requests to travel through Symfony’s normal error page.

Upgrade priority: if the app sits behind Pantheon’s Fastly-based Global CDN or any CDN that loosely honours no-store, this release is important. Before 1.3.0, a challenge page could be cached at the edge with a single-use challenge, so only the first visitor could solve it and everyone else looped.

Implementation Patterns

Configuration-driven rules are the default workflow. Define path, IP, ASN, and rate-limit rules in bundle config, then verify them with kanopi:firewall:check. Keep rules against normalised paths; as of the ^2.36 library floor, //wp-json/... and /%77p-json/... are normalised before rules see them.

Let the bundle own responses when using mode: exception. In that mode the bundle writes block, lockdown, challenge, redirect, and solved-challenge responses. Do not half-write your own response in a listener unless you are prepared to reproduce the full cache-header set. If you use blocked_response: http_exception, the headers travel with the exception, so your Symfony error page carries them too.

Use query_count for crawler and facet abuse. The new query_count rule variable, available with kanopi/firewall ^2.36, is useful for capping query-string crawling without blocking normal pagination. It fits well alongside rate limits on search/filter endpoints.

Gate CI with the check command and its real exit codes. The command now exits 64 when it cannot read configuration, instead of 2. The full set is:

  • 0 allowed
  • 1 blocked
  • 2 challenged
  • 3 redirected
  • 64 unreadable configuration
  • 70 internal/script error

A CI assertion that a URL is challenged should fail on 64, not pass because it saw 2. If you run checks in a subdirectory install, use the now-declared --script-name option so the CLI check sees the same path shape as the app.

Surface challenge notices deliberately. challenge.notice in config and RequestChallenged::addNotice() from a Symfony listener both reach the challenge page. Use the config value for static messaging and the listener when the notice depends on request context, tenant, or rule that fired.

Test ASN and rate-limit rules after upgrading. ASN rules such as asn:16509 previously never fired. After moving to ^2.36, they will start matching. Similarly, rate-limit keys that name a field with a capital letter now count that field correctly instead of sharing one counter across every visitor. If you relied on the old shared-counter behaviour—even accidentally—expect traffic shaping to change.

Deployment pattern: change config → clear Symfony cache → run kanopi:firewall:check against representative URLs → run the doctor → spot-check response headers with curl -I. This is especially important on CDN-fronted environments.

Gotchas and Tips

Do not install this in a Laravel app expecting Laravel integration. It is a Symfony bundle. The underlying kanopi/firewall library and the rule concepts are portable, but the bundle’s commands, config, and response writing are Symfony-specific.

Preserve the full no-store header set if you write your own responses. The 1.3.0 fix sends:

Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0
Pragma: no-cache
Expires: 0
Surrogate-Control: no-store
CDN-Cache-Control: no-store

If you override or wrap firewall responses, do not reduce this to Cache-Control: no-store alone. That was the exact condition that let Pantheon’s CDN cache a single-use challenge.

Avoid global.path_source: script_name in Symfony. That setting is intended for WordPress’s directly served files. A Symfony app runs public/index.php, and in a subdirectory install script_name puts the subdirectory in front of every path. The doctor now warns about this; take the warning seriously rather than suppressing it.

The exit-code change can break CI in both directions. A pipeline that treated 2 as “challenged” may now see 64 for an unreadable config. That is the intended fix: a gate should not pass on an application with no usable rules. Update scripts and help text assumptions.

ASN rules becoming live is a behaviour change. After the upgrade, rules that were previously inert may start blocking or challenging traffic. Roll out with logging or a permissive phase first if ASN rules are in production config.

Capitalised rate-limit field names are now meaningful. A key naming a field with a capital letter counts that field instead of sharing one counter across all visitors. Prefer lowercase field names for predictability, and re-check limits after upgrade.

query_count requires the new library floor. Do not copy a query_count rule into an app still on kanopi/firewall ^2.33; it will not behave as expected.

Solved-challenge redirects are now constrained. The library fix in 2.35.0 prevents a solved challenge from redirecting off-site. If you had a custom flow depending on an external post-solve redirect, re-test it.

Debug with headers, not just status codes. Use curl -I against a challenged URL and confirm the full cache-header set is present. Use kanopi:firewall:check for rule outcomes, and the doctor for configuration warnings. For deeper integration, listen to RequestChallenged and add notices rather than replacing the bundle’s response.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console