webrium/xzeroprotect 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

webrium/xzeroprotect

Composer 安装命令:

composer require webrium/xzeroprotect

包简介

A lightweight, file-based PHP firewall library for protecting web applications from bots, scanners, and common attacks.

README 文档

README


██╗  ██╗███████╗███████╗██████╗  ██████╗ ██████╗ ██████╗  ██████╗ ████████╗███████╗ ██████╗████████╗
╚██╗██╔╝╚══███╔╝██╔════╝██╔══██╗██╔═══██╗██╔══██╗██╔══██╗██╔═══██╗╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝
 ╚███╔╝   ███╔╝ █████╗  ██████╔╝██║   ██║██████╔╝██████╔╝██║   ██║   ██║   █████╗  ██║        ██║   
 ██╔██╗  ███╔╝  ██╔══╝  ██╔══██╗██║   ██║██╔═══╝ ██╔══██╗██║   ██║   ██║   ██╔══╝  ██║        ██║   
██╔╝ ██╗███████╗███████╗██║  ██║╚██████╔╝██║      ██║  ██║╚██████╔╝   ██║   ███████╗╚██████╗   ██║   
╚═╝  ╚═╝╚══════╝╚══════╝╚═╝  ╚═╝ ╚═════╝ ╚═╝     ╚═╝  ╚═╝ ╚═════╝    ╚═╝   ╚══════╝ ╚═════╝   ╚═╝   

A lightweight, file-based PHP firewall for the modern web.
No database. No external services. No compromises.


PHP Composer License Zero Dependencies


Why xZeroProtect?

Every day, bots crawl your application looking for exposed .env files, WordPress admin panels, SQL injection vectors, and known CVEs — even if you're not running WordPress. xZeroProtect stops them at the PHP layer with zero external dependencies, no database connection, and a clean API you can tune in minutes.

  • File-based — everything stored on disk; no MySQL, Redis, or memcached required
  • Zero dependencies — pure PHP 8.0+, nothing else
  • Composable — enable, disable, or extend every detection module independently
  • Learning mode — log threats without blocking, perfect for tuning before going live
  • Apache-aware — optionally write permanent bans into .htaccess so Apache rejects them before PHP even starts

Installation

composer require webrium/xzeroprotect

Quick Start

Add these two lines at the very top of your index.php or bootstrap file:

<?php
require 'vendor/autoload.php';

use Webrium\XZeroProtect\XZeroProtect;

XZeroProtect::init()->run();

That's it. Default rules are active immediately.

Note: init() stores the instance internally. You can retrieve it from anywhere in your application using XZeroProtect::getInstance() — no need to pass $firewall around.

Configuration

Every option has a sensible default. Override only what you need:

$firewall = XZeroProtect::init([

    // 'production' → block & log  |  'learning' → log only  |  'off' → disabled
    'mode'         => 'production',

    // Where ban files, rate data, and logs are stored
    'storage_path' => __DIR__ . '/storage/firewall',

    // --- Rate limiting ---
    'rate_limit' => [
        'enabled'      => true,
        'max_requests' => 60,   // requests per window
        'per_seconds'  => 60,   // window size in seconds
    ],

    // --- Automatic banning ---
    'auto_ban' => [
        'enabled'              => true,
        'violations_threshold' => 10,     // violations before a ban is issued
        'ban_duration'         => 86400,  // ban length in seconds (24 h)
        'permanent_after_bans' => 3,      // escalate to permanent after N bans
    ],

    // --- Apache integration ---
    'apache_blocking' => false,
    'htaccess_path'   => __DIR__ . '/.htaccess',

    // --- Reverse proxies / CDNs (e.g. Cloudflare, Nginx, load balancers) ---
    // Leave empty to always use REMOTE_ADDR (safest if the server is
    // reachable directly). Add proxy IPs/CIDRs to read the real client IP
    // from CF-Connecting-IP / True-Client-IP / X-Real-IP / X-Forwarded-For
    // when the request comes from one of these proxies. Use ['*'] to trust
    // these headers regardless of REMOTE_ADDR (only if the server is NOT
    // directly reachable).
    'trusted_proxies' => [],

    // --- Always-allow list ---
    'whitelist' => [
        'ips'   => ['127.0.0.1', '10.0.0.0/8'],
        'paths' => ['/health', '/ping'],
    ],

    // --- Response sent to blocked clients ---
    'block_response' => [
        'code'    => 403,
        'message' => 'Access Denied',
    ],

    // --- Toggle individual detection modules ---
    'checks' => [
        'crawler_check' => true,   // exempt verified crawlers from all checks
        'rate_limit'    => true,
        'blocked_path'  => true,
        'user_agent'    => true,
        'payload'       => true,
        'custom_rules'  => true,
    ],

    // --- Log settings ---
    'log' => [
        'enabled'       => true,
        'max_file_size' => 10,   // MB — auto-rotated when exceeded
        'keep_days'     => 30,
    ],

]);

$firewall->run();

Detection Modules

Path Detection

Blocks requests targeting sensitive or non-existent paths. Because a modern routed PHP app has no .php files in the URL, you can add that pattern to immediately reject the flood of index.php?id= scanner probes.

// Add individual patterns
$firewall->patterns->addPath('.php');
$firewall->patterns->addPath('/control-panel');

// Add many at once
$firewall->patterns->addPaths(['.asp', '.jsp', '/backup', '/staging']);

// Remove a default pattern you want to allow
$firewall->patterns->removePath('xmlrpc');
View all default blocked paths
Category Patterns
CMS panels wp-admin, wp-login, wp-config, xmlrpc, administrator, typo3
Config exposure .env, .git, .svn, .htaccess, .htpasswd, web.config
DB tools phpmyadmin, pma, adminer, dbadmin
Dangerous files .sql, .bak, .backup, .old, dump.sql
Path traversal ../, ..%2f, %2e%2e
Web shells shell.php, c99.php, r57.php, webshell
Script extensions .asp, .aspx, .jsp, .cfm, .cgi
Info disclosure phpinfo, server-status, server-info
Install artifacts setup.php, install.php, readme.html

Note: .php is not blocked by default to avoid false positives on applications that serve raw PHP files. Add it explicitly if your app uses modern routing: $firewall->patterns->addPath('.php')

User-Agent Detection

Identifies and blocks known scanner, brute-force, and exploit tool signatures. Empty User-Agent strings are treated as suspicious by default.

$firewall->patterns->addAgent('custom-bad-bot');
$firewall->patterns->removeAgent('curl'); // allow curl if your API clients use it
View default blocked agents

sqlmap · nikto · nessus · acunetix · netsparker · masscan · nmap · zgrab · dirbuster · gobuster · feroxbuster · wfuzz · ffuf · hydra · metasploit · semrushbot · ahrefsbot · libwww-perl · and more

Note: curl, wget, python-requests, and go-http-client are not blocked by default because they are also used by legitimate API clients. Add them explicitly if needed:

$firewall->patterns->addAgent('curl/');
$firewall->patterns->addAgent('wget/');
$firewall->patterns->addAgent('python-requests');
$firewall->patterns->addAgent('go-http-client');

Payload Detection

Scans GET parameters, POST body, raw input, and cookies for attack signatures using compiled regular expressions.

// Add a custom pattern
$firewall->patterns->addPayload('/CUSTOM_EXPLOIT/i', 'my_label');

// Remove a built-in pattern
$firewall->patterns->removePayload('sqli_union');
View default payload rules
Label Detects
sqli_union UNION [ALL] SELECT
sqli_select SELECT ... FROM
sqli_drop DROP TABLE/DATABASE
sqli_sleep SLEEP(n) time-based blind
sqli_benchmark BENCHMARK(...)
sqli_comment --, #, /* */ injection comments
xss_script <script tags
xss_onerror Inline event handlers (onerror=, onclick=, ...)
xss_javascript javascript: protocol
traversal ../ path traversal
php_exec system(), exec(), shell_exec(), ...
php_eval eval(base64_decode(...))
lfi /etc/passwd, /etc/shadow
rfi Remote file inclusion URLs
cmd_injection Shell metacharacters + commands

Rate Limiting

Sliding-window counter stored per-IP on disk. No Redis required.

$firewall = XZeroProtect::init([
    'rate_limit' => [
        'max_requests' => 30,
        'per_seconds'  => 10,
    ],
]);

Crawler Detection

Trusted web crawlers (Googlebot, Bingbot, and others) are identified and exempted from all firewall checks — including rate limiting and auto-ban. This prevents legitimate bots from being accidentally blocked.

For crawlers like Googlebot and Bingbot, identity is confirmed via double-DNS verification before granting trust:

  1. Resolve the visitor IP to a hostname via reverse DNS
  2. Confirm the hostname ends with the expected suffix (e.g. .googlebot.com)
  3. Re-resolve that hostname back to an IP
  4. Confirm the re-resolved IP matches the original visitor IP

This is the verification method recommended by Google and Bing in their official documentation. Anyone can fake a User-Agent — DNS cannot be faked.

Social crawlers (Twitterbot, LinkedInBot, Slackbot, etc.) are trusted by User-Agent only, as they do not publish verifiable IP ranges or rDNS suffixes.

// Add a custom trusted crawler
$firewall->crawlers->addCrawler(
    name: 'MyCrawler',
    uaContains: 'mycrawlerbot',
    verifyRdns: false
);

// Remove a crawler from the trusted list
$firewall->crawlers->removeCrawler('Googlebot');

// Disable crawler detection entirely
$firewall->disableCheck('crawler_check');
View default trusted crawlers
Crawler UA contains DNS verified
Googlebot googlebot .googlebot.com
Google Other google .google.com
Bingbot bingbot .search.msn.com
Yahoo Slurp yahoo! slurp .crawl.yahoo.net
DuckDuckBot duckduckbot
Yandex yandexbot .yandex.com
Baidu baiduspider .baidu.com
Applebot applebot .applebot.apple.com
Facebook facebookexternalhit .facebook.com
Twitterbot twitterbot
LinkedInBot linkedinbot
WhatsApp whatsapp
Telegram telegrambot
Slackbot slackbot
Discordbot discordbot
Uptimerobot uptimerobot
Pingdom pingdom

IP Management

// Temporary ban (24 h default)
$firewall->ip->ban('1.2.3.4');
$firewall->ip->ban('1.2.3.4', reason: 'manual review', duration: 3600);

// Permanent ban
$firewall->ip->banPermanent('1.2.3.4', reason: 'confirmed attacker');

// Remove a ban
$firewall->ip->unban('1.2.3.4');

// Inspect
$firewall->ip->isBanned('1.2.3.4');    // bool
$firewall->ip->getBanInfo('1.2.3.4');  // array|null  { ip, reason, banned_at, expires, bans_count }
$firewall->ip->getAllBans();            // array of all active bans

// Whitelist — supports exact IPs and CIDR notation (IPv4 & IPv6)
$firewall->ip->whitelist('10.0.0.0/8');
$firewall->ip->whitelist('2001:db8::/32');

Custom Rules

Register your own logic as first-class firewall rules with full access to the request object.

use Webrium\XZeroProtect\RuleResult;

// Block requests with a .php extension (for fully-routed apps)
$firewall->rules->add('no-php-extension', function ($request) {
    if (str_ends_with($request->path(), '.php')) {
        return RuleResult::block('PHP extension not valid on this server');
    }
    return RuleResult::pass();
});

// Log suspicious POST requests without logging a violation
$firewall->rules->add('post-no-referer', function ($request) {
    if ($request->method === 'POST' && empty($request->referer)) {
        return RuleResult::log('POST without Referer header');
    }
    return RuleResult::pass();
}, priority: 10);  // lower = runs first

// Manage rules at runtime
$firewall->rules->disable('no-php-extension');
$firewall->rules->enable('no-php-extension');
$firewall->rules->remove('no-php-extension');

RuleResult options:

Method Effect
RuleResult::pass() Allow the request, continue checking
RuleResult::block(reason: '...') Block immediately and log
RuleResult::log(reason: '...') Log without blocking

Apache Integration

When apache_blocking is enabled, permanently banned IPs are written to .htaccess. Apache drops those connections before PHP starts — zero PHP overhead for known bad actors.

$firewall = XZeroProtect::init([
    'apache_blocking' => true,
    'htaccess_path'   => __DIR__ . '/.htaccess',
]);

// Sync all current permanent bans to .htaccess
$firewall->apache->sync(array_keys($firewall->ip->getAllBans()));

// Block/unblock a single IP in .htaccess
$firewall->apache->block('5.6.7.8');
$firewall->apache->unblock('5.6.7.8');

Generated .htaccess block:

# xZeroProtect:start
# Auto-generated by xZeroProtect — do not edit this block manually
<RequireAll>
    Require all granted
    Require not ip 1.2.3.4
    Require not ip 5.6.7.8
</RequireAll>
# xZeroProtect:end

Logging

// Read the most recent attack entries (newest first)
$logs = $firewall->logger->recent(limit: 100);

// Clean up rotated backup log files older than retention period
$firewall->logger->cleanup();

Accessing the firewall from outside bootstrap

Because init() stores the instance as a singleton, you can retrieve it from any controller, admin panel, or CLI script without passing $firewall as a variable:

use Webrium\XZeroProtect\XZeroProtect;

// In bootstrap / index.php
XZeroProtect::init()->run();

// ---

// In any other file (e.g. admin panel, dashboard controller)
$firewall = XZeroProtect::getInstance();

$logs    = $firewall->logger->recent(limit: 100);
$bans    = $firewall->ip->getAllBans();
$isBanned = $firewall->ip->isBanned('1.2.3.4');

If getInstance() is called before init(), it throws a clear RuntimeException:

xZeroProtect has not been initialized. Call XZeroProtect::init() first.

Log entries are plain-text, one per line:

2024-11-15 14:32:01 | ip=185.220.101.5 | type=sqli_union | uri=/search?q=1+UNION+SELECT | reason=Payload match: sqli_union | ua=sqlmap/1.7

Disabling Individual Checks

// At init time
XZeroProtect::init([
    'checks' => [
        'user_agent' => false,  // disable UA checking for this app
    ],
]);

// Or at runtime
$firewall->disableCheck('user_agent');
$firewall->enableCheck('user_agent');

Available check keys: crawler_check · rate_limit · blocked_path · user_agent · payload · custom_rules

Learning Mode

Deploy in learning mode first. All attacks are logged but nothing is blocked. Review the logs, tune your rules, then switch to production.

// During tuning
XZeroProtect::init(['mode' => 'learning'])->run();

// Once satisfied
XZeroProtect::init(['mode' => 'production'])->run();

Visitor Tracking

After all firewall checks pass, xZeroProtect can record verified real visits — bots, scanners, and suspicious requests are already filtered out before this runs.

Tracking is opt-in and disabled by default. Enable it by passing a closure to enableTracking() before calling run(). The closure receives a VisitInfo object; how you store the data is entirely up to you.

use Webrium\XZeroProtect\XZeroProtect;
use Webrium\XZeroProtect\VisitInfo;

$firewall = XZeroProtect::init();

$firewall->enableTracking(function (VisitInfo $visit) {
    // Store in your database however you like
    $pdo->prepare("
        INSERT INTO visits
            (ip, path, method, referer, user_agent,
             browser, browser_version, os, os_version,
             device_type, fingerprint, visited_at)
        VALUES
            (:ip, :path, :method, :referer, :user_agent,
             :browser, :browser_ver, :os, :os_ver,
             :device_type, :fingerprint, :visited_at)
    ")->execute([
        ':ip'          => $visit->ip,
        ':path'        => $visit->path,
        ':method'      => $visit->method,
        ':referer'     => $visit->referer,
        ':user_agent'  => $visit->userAgent,
        ':browser'     => $visit->device->browser,
        ':browser_ver' => $visit->device->browserVersion,
        ':os'          => $visit->device->os,
        ':os_ver'      => $visit->device->osVersion,
        ':device_type' => $visit->device->type,
        ':fingerprint' => $visit->fingerprint,
        ':visited_at'  => $visit->date(),
    ]);
});

$firewall->run();

VisitInfo properties

Property Type Description
$visit->ip string Visitor IP address
$visit->uri string Full URI including query string
$visit->path string URI path without query string
$visit->method string HTTP method (GET, POST, ...)
$visit->userAgent string Raw User-Agent header
$visit->referer string HTTP Referer header
$visit->timestamp int Unix timestamp
$visit->fingerprint string SHA-256 unique visitor identifier (see below)
$visit->device DeviceInfo Parsed browser, OS, and device type
$visit->date() string Formatted timestamp — default Y-m-d H:i:s
$visit->toArray() array All fields as a flat array, ready for DB insert

DeviceInfo properties

Accessible via $visit->device:

Property Type Example
->browser string Chrome, Firefox, Safari, Edge, Opera
->browserVersion string 124.0.0.0
->os string Windows, macOS, Android, iOS, Linux
->osVersion string 10/11, 17.0, 13
->type string desktop, mobile, tablet
->isDesktop bool true / false
->isMobile bool true / false
->isTablet bool true / false

Unique visitor fingerprinting

$visit->fingerprint is a SHA-256 hash of the visitor's IP, User-Agent, and the current date. This means:

  • The same visitor on the same day always gets the same fingerprint — useful for deduplicating page hits into unique daily visits.
  • The fingerprint resets the next day — no long-term tracking.
  • The raw IP is never stored in the fingerprint — it cannot be reversed.
// Count only unique visitors per day
$firewall->enableTracking(function (VisitInfo $visit) use ($pdo) {
    $exists = $pdo->prepare("SELECT 1 FROM visits WHERE fingerprint = ? AND DATE(visited_at) = CURDATE()")
                  ->execute([$visit->fingerprint]);
    if (!$exists->fetchColumn()) {
        // First visit of the day for this visitor
        $pdo->prepare("INSERT INTO visits ...")->execute($visit->toArray());
    }
});

Manage tracking at runtime

$firewall->disableTracking();
$firewall->isTrackingEnabled(); // bool

Architecture

xzeroprotect/
├── src/
│   ├── XZeroProtect.php      Main class & orchestrator
│   ├── Request.php           HTTP request context
│   ├── Storage.php           File-based persistence (bans, rate, violations, logs)
│   ├── IPManager.php         Ban/whitelist management with CIDR support
│   ├── PatternDetector.php   Path, User-Agent, and payload matching
│   ├── RateLimiter.php       Sliding-window rate limiter
│   ├── RuleEngine.php        Custom rule registration & execution
│   ├── ApacheBlocker.php     .htaccess read/write
│   ├── CrawlerVerifier.php   Trusted crawler detection with double-DNS
│   ├── Logger.php            Attack logging with rotation
│   ├── VisitInfo.php         Verified visit data object (tracking)
│   └── DeviceInfo.php        Browser, OS, and device type parser
├── config/
│   └── config.php            Default configuration
├── rules/
│   ├── paths.php             Default blocked path patterns
│   ├── agents.php            Default blocked User-Agent signatures
│   ├── payloads.php          Default attack payload patterns (PCRE)
│   └── crawlers.php          Trusted crawler definitions (UA + rDNS config)
└── tests/
    └── XZeroProtectTest.php  PHPUnit test suite

Running Tests

composer install
composer test

# With detailed output
./vendor/bin/phpunit --testdox

Requirements

  • PHP 8.0 or higher
  • Write permission on the storage directory

License

Released under the MIT License.
Built by Webrium.

webrium/xzeroprotect 适用场景与选型建议

webrium/xzeroprotect 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 9 次下载、GitHub Stars 达 2, 最近一次更新时间为 2026 年 02 月 27 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「php」 「security」 「firewall」 「waf」 「bot-protection」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 webrium/xzeroprotect 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 webrium/xzeroprotect 我们能提供哪些服务?
定制开发 / 二次开发

基于 webrium/xzeroprotect 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 9
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 2
  • 点击次数: 38
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 2
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-02-27