PHP项目地域限流如何封禁高风险地区访问

wen PHP项目 30

本文目录导读:

PHP项目地域限流如何封禁高风险地区访问

  1. IP地址库方案
  2. 中间件/框架集成方案
  3. Nginx层面封禁(推荐生产环境)
  4. 全面解决方案示例
  5. 注意事项
  6. 推荐方案

在PHP项目中实现地域限流(封禁高风险地区访问)通常有以下几种方案:

IP地址库方案

使用IP数据库(推荐)

<?php
class GeoBlock {
    private $highRiskRegions = ['XX', 'YY']; // 高风险地区代码
    public function checkAccess($ip) {
        // 使用IP数据库查询地理位置
        $location = $this->getLocation($ip);
        if ($location && in_array($location['country_code'], $this->highRiskRegions)) {
            return false;
        }
        return true;
    }
    private function getLocation($ip) {
        // 使用纯真IP库或GeoIP2等
        // 示例使用GeoIP2
        $reader = new GeoIp2\Database\Reader('/path/to/GeoLite2-Country.mmdb');
        try {
            $record = $reader->country($ip);
            return [
                'country_code' => $record->country->isoCode,
                'country_name' => $record->country->name
            ];
        } catch (\Exception $e) {
            return null;
        }
    }
}

使用第三方API(适合低并发)

<?php
function checkByApi($ip) {
    $apiKey = 'YOUR_API_KEY';
    $url = "https://api.ip2location.com/v2/?ip={$ip}&key={$apiKey}&format=json";
    $response = file_get_contents($url);
    $data = json_decode($response, true);
    // 检查是否为高风险地区
    $highRiskCodes = ['CN', 'RU', 'KP']; // 示例
    if (in_array($data['country_code'], $highRiskCodes)) {
        return false;
    }
    return true;
}

中间件/框架集成方案

Laravel框架示例

<?php
// app/Http/Middleware/GeoBlockMiddleware.php
namespace App\Http\Middleware;
use Closure;
use Stevebauman\Location\Facades\Location;
class GeoBlockMiddleware
{
    public function handle($request, Closure $next)
    {
        $ip = $request->ip();
        $position = Location::get($ip);
        if ($position && in_array($position->countryCode, ['RU', 'CN', 'KP'])) {
            abort(403, 'Access denied from your region');
        }
        return $next($request);
    }
}

Nginx层面封禁(推荐生产环境)

使用ngx_http_geoip_module

# nginx.conf
http {
    geoip_country /path/to/GeoIP.dat;
    map $geoip_country_code $blocked_country {
        default 0;
        RU 1;
        CN 1;
        KP 1;
    }
    server {
        location / {
            if ($blocked_country) {
                return 403;
            }
            # 正常逻辑
        }
    }
}

使用IP集(适合固定IP列表)

# nginx.conf
http {
    geo $block_region {
        ranges;
        default 0;
        # 俄罗斯IP段示例
        46.0.0.0/8 1;
        95.0.0.0/8 1;
        # 添加其他IP段
    }
    server {
        if ($block_region) {
            return 403;
        }
    }
}

全面解决方案示例

<?php
class ComprehensiveGeoBlocker {
    private $geoDbPath;
    private $highRiskRegions;
    private $cache;
    public function __construct() {
        $this->geoDbPath = '/path/to/GeoIP.mmdb';
        $this->highRiskRegions = [
            'RU' => 'Russia',
            'KP' => 'North Korea',
            'IR' => 'Iran',
            'SY' => 'Syria',
            'CU' => 'Cuba'
        ];
        $this->initCache();
    }
    public function handle() {
        $ip = $this->getClientIP();
        // 检查缓存
        if ($this->isCached($ip)) {
            return $this->getCachedResult($ip);
        }
        $result = $this->checkIP($ip);
        $this->setCache($ip, $result);
        if (!$result) {
            $this->logBlockedAccess($ip);
            http_response_code(403);
            exit('Access denied');
        }
    }
    private function getClientIP() {
        $headers = [
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_REAL_IP',
            'HTTP_CLIENT_IP',
            'REMOTE_ADDR'
        ];
        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $ips = explode(',', $_SERVER[$header]);
                $ip = trim($ips[0]);
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    return $ip;
                }
            }
        }
        return $_SERVER['REMOTE_ADDR'];
    }
    private function checkIP($ip) {
        try {
            $reader = new \MaxMind\Db\Reader($this->geoDbPath);
            $data = $reader->get($ip);
            if ($data && isset($data['country']['iso_code'])) {
                $countryCode = $data['country']['iso_code'];
                return !in_array($countryCode, array_keys($this->highRiskRegions));
            }
            return true; // 无法确定地区时放行
        } catch (\Exception $e) {
            return true; // 出错时放行
        }
    }
    private function initCache() {
        // 使用Redis或文件缓存
        $this->cache = new \Predis\Client();
    }
    private function isCached($ip) {
        return $this->cache->exists("geo_block:{$ip}");
    }
    private function getCachedResult($ip) {
        return $this->cache->get("geo_block:{$ip}") === 'true';
    }
    private function setCache($ip, $result) {
        $this->cache->setex("geo_block:{$ip}", 3600, $result ? 'true' : 'false');
    }
    private function logBlockedAccess($ip) {
        $logEntry = [
            'time' => date('Y-m-d H:i:s'),
            'ip' => $ip,
            'url' => $_SERVER['REQUEST_URI'],
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? ''
        ];
        file_put_contents(
            '/var/log/geo_blocked.log',
            json_encode($logEntry) . PHP_EOL,
            FILE_APPEND
        );
    }
}
// 使用
$blocker = new ComprehensiveGeoBlocker();
$blocker->handle();

注意事项

  1. 性能优化

    • 使用CDN/WAF级别进行地域封禁
    • 缓存IP地理位置结果
    • 使用内存数据库(Redis)存储黑名单
  2. 法律合规

    • 确保符合当地数据保护法规
    • 披露IP地址使用政策
  3. 误判处理

    • 保留白名单机制
    • 允许用户申诉
  4. 监控告警

    // 监控封禁情况
    if ($blockedCount > $threshold) {
        sendAlert("大量地域封禁触发,可能误判或遭受攻击");
    }
  5. 混合策略

    • 结合CDN(CloudFlare等)的地域封禁功能
    • 使用Web应用防火墙(WAF)
    • 定期更新IP数据库

推荐方案

对于生产环境,推荐:

  1. 第一层:CDN/WAF层面的地域封禁(性能最好)
  2. 第二层:Nginx GeoIP模块(快速有效)
  3. 第三层:PHP应用层封禁(最灵活但性能损耗较大)

根据项目规模和预算选择合适的方案组合。

抱歉,评论功能暂时关闭!