flowd/phirewall

A PHP Firewall and rate limiter based on PSR-7 and PSR-15 middleware (safelists, blocklists, throttles, fail2ban)

Installs: 1 018

Dependents: 1

Suggesters: 0

Security: 0

Stars: 2

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/flowd/phirewall

0.2.0 2026-01-27 21:39 UTC

This package is not auto-updated.

Last update: 2026-02-05 00:16:12 UTC


README

Phirewall Logo

Protect your PHP application from brute force, DDoS, SQL injection, XSS, and bot attacks with a single middleware.

Phirewall is a PSR-15 middleware that provides comprehensive application-layer protection. It's lightweight, framework-agnostic, and easy to configure.

Why Phirewall?

  • Simple Setup - Add protection in minutes with sensible defaults
  • Multiple Attack Vectors - Rate limiting, brute force protection, OWASP rules, bot detection
  • Framework Agnostic - Works with any PSR-15 compatible framework (Laravel, Symfony, Slim, Mezzio, etc.)
  • Production Ready - Redis support for multi-server deployments
  • Observable - PSR-14 events for logging, metrics, and alerting

Quick Start

composer require flowd/phirewall
use Flowd\Phirewall\Config;
use Flowd\Phirewall\Middleware;
use Flowd\Phirewall\KeyExtractors;
use Flowd\Phirewall\Store\InMemoryCache;

// Create the firewall
$config = new Config(new InMemoryCache());

// Allow health checks to bypass all rules
$config->safelist('health', fn($req) => $req->getUri()->getPath() === '/health');

// Block common scanner paths
$config->blocklist('scanners', fn($req) => str_starts_with($req->getUri()->getPath(), '/wp-admin'));

// Rate limit: 100 requests per minute per IP
$config->throttle('api', limit: 100, period: 60, key: KeyExtractors::ip());

// Ban IP after 5 failed logins in 5 minutes
$config->fail2ban('login', threshold: 5, period: 300, ban: 3600,
    filter: fn($req) => $req->getHeaderLine('X-Login-Failed') === '1',
    key: KeyExtractors::ip()
);

// Add to your middleware stack
$middleware = new Middleware($config);

Add the middleware to your PSR-15 pipeline. All requests will be evaluated against your rules before reaching your application.

Try It Now

Run one of the included examples to see Phirewall in action:

# Basic setup demo
php examples/01-basic-setup.php

# See brute force protection
php examples/02-brute-force-protection.php

# Test SQL injection blocking
php examples/04-sql-injection-blocking.php

# Full production setup
php examples/08-comprehensive-protection.php

Examples

The examples/ folder contains 15 runnable examples:

# Example Description
01 basic-setup Minimal configuration to get started
02 brute-force-protection Fail2Ban-style login protection
03 api-rate-limiting Tiered rate limits for APIs
04 sql-injection-blocking OWASP-style SQLi detection
05 xss-prevention Cross-Site Scripting protection
06 bot-detection Scanner and malicious bot blocking
07 ip-blocklist File-backed IP/CIDR blocklists
08 comprehensive-protection Production-ready multi-layer setup
09 observability-monolog Event logging with Monolog
10 observability-opentelemetry Distributed tracing with OpenTelemetry
11 redis-storage Redis backend for multi-server deployments
12 apache-htaccess Apache .htaccess IP blocking
13 benchmarks Storage backend performance comparison
14 owasp-crs-files Loading OWASP CRS rules from files
15 in-memory-pattern-backend Configuration-based CIDR/IP blocklists

Features

Protection Layers

Feature Description
Safelists Bypass all checks for trusted requests (health checks, internal IPs)
Blocklists Immediately deny suspicious requests (403)
Throttling Rate limit by IP, user, API key, or custom key (429)
Fail2Ban Auto-ban after repeated failures
OWASP CRS SQL injection, XSS, and PHP injection detection
Pattern Backends File/Redis-backed blocklists with IP, CIDR, path, and header patterns

Observability

  • PSR-14 Events - SafelistMatched, BlocklistMatched, ThrottleExceeded, Fail2BanBanned
  • Diagnostics Counters - Per-rule statistics for monitoring
  • Standard Headers - X-RateLimit-*, Retry-After, X-Phirewall-*

Storage Backends

Backend Use Case
InMemoryCache Development, testing, single requests
ApcuCache Single-server production
RedisCache Multi-server production

Documentation

For detailed documentation, see the docs/ folder:

Installation

composer require flowd/phirewall

Optional Dependencies

# For Redis-backed distributed counters (multi-server)
composer require predis/predis

# For Monolog logging integration
composer require monolog/monolog

APCu: Enable the PHP extension and set apc.enable_cli=1 for CLI testing.

Response Headers

When a request is blocked:

Header Description
X-Phirewall Block type: blocklist, throttle, fail2ban
X-Phirewall-Matched Rule name that triggered
Retry-After Seconds until rate limit resets (429 only)

Enable $config->enableRateLimitHeaders() for standard X-RateLimit-* headers.

Client IP Behind Proxies

When behind load balancers or CDNs, use TrustedProxyResolver:

use Flowd\Phirewall\Http\TrustedProxyResolver;
use Flowd\Phirewall\KeyExtractors;

$resolver = new TrustedProxyResolver([
    '10.0.0.0/8',      // Internal network
    '172.16.0.0/12',   // Docker
]);

$config->throttle('api', limit: 100, period: 60,
    key: KeyExtractors::clientIp($resolver)
);

Custom Responses

Customize blocked responses while keeping standard headers:

$config->blocklistedResponse(function (string $rule, string $type, $req) {
    return new Response(403, ['Content-Type' => 'application/json'],
        json_encode(['error' => 'Blocked', 'rule' => $rule])
    );
});

$config->throttledResponse(function (string $rule, int $retryAfter, $req) {
    return new Response(429, ['Content-Type' => 'application/json'],
        json_encode(['error' => 'Rate limited', 'retry_after' => $retryAfter])
    );
});

OWASP Core Rule Set

Load OWASP-style rules for SQL injection, XSS, and more:

use Flowd\Phirewall\Owasp\SecRuleLoader;

$rules = SecRuleLoader::fromString(<<<'CRS'
SecRule ARGS "@rx (?i)\bunion\b.*\bselect\b" "id:942100,phase:2,deny,msg:'SQLi'"
SecRule ARGS "@rx (?i)<script[^>]*>" "id:941100,phase:2,deny,msg:'XSS'"
CRS);

$config->owaspBlocklist('owasp', $rules);

Or load from files:

$rules = SecRuleLoader::fromDirectory('/path/to/crs-rules');

See 04-sql-injection-blocking.php and 05-xss-prevention.php for complete examples.

Real-World Recipes

API Rate Limiting

// Global limit
$config->throttle('global', limit: 1000, period: 60, key: KeyExtractors::ip());

// Burst detection
$config->throttle('burst', limit: 30, period: 5, key: KeyExtractors::ip());

// Higher limits for authenticated users
$config->throttle('user', limit: 5000, period: 60, key: KeyExtractors::header('X-User-Id'));

Login Protection

// Throttle login attempts
$config->throttle('login', limit: 10, period: 60, key: function($req) {
    return $req->getUri()->getPath() === '/login'
        ? $req->getServerParams()['REMOTE_ADDR']
        : null;
});

// Ban after failures
$config->fail2ban('login-ban', threshold: 5, period: 300, ban: 3600,
    filter: fn($req) => $req->getHeaderLine('X-Login-Failed') === '1',
    key: KeyExtractors::ip()
);

Bot Detection

$scanners = ['sqlmap', 'nikto', 'nmap', 'burp', 'dirbuster'];

$config->blocklist('scanners', function($req) use ($scanners) {
    $ua = strtolower($req->getHeaderLine('User-Agent'));
    foreach ($scanners as $scanner) {
        if (str_contains($ua, $scanner)) return true;
    }
    return false;
});

Development

# Run tests
composer test

# Fix code style
composer fix

# Mutation testing
composer test:mutation

Sponsors

This project received funding from TYPO3 Association through its Community Budget program.

Read more

License

Dual licensed under LGPL-3.0-or-later and proprietary. See LICENSE for details.