IP アクセス制御: PHP を使用して IP ファイアウォールを実装する方法をナニー スタイルで教えます

藏色散人
リリース: 2023-04-11 07:22:01
転載
3742 人が閲覧しました

最近、ある要件が発生しました。サーバーの 1 つが常にポート スキャンと悪意のあるログイン攻撃の対象になっています。これについてはどうすればよいですか?イントラネット分離、強化されたパスワード認証、証明書ログイン、およびファイアウォールiptablesの設定以外に、オンラインで利用できるソリューションはないようです。ちなみに、私は要塞ホスト ソリューションも使用しています。

これらの解決策はどれも実際には私の問題を解決しません。これはパブリック ネットワーク サーバーであり、複雑なネットワーク構造を持っていないため、イントラネットの分離を確立できません。アカウントのパスワードポリシーを調整することで解決するのは当然ですが、手動で行うのは面倒で、普段パソコンを買い替えるのですが、パスワードを変更すると会社と自宅の両方のパソコンを更新する必要があり、非常に面倒です。ファイアウォールの設定は当然基本的な運用保守作業ですが、iptablesの設定が面倒なのでufwツールの方が良い、firewall-cmdはさらに面倒で、大きな問題点があります。ご存知のとおり、みんなの送信ネットワーク IP は頻繁に変更されます。最終的にはコマンド ラインで 1 文字ずつ設定しましたが、長いスリープの後はすべて無駄でした。バスティオン マシンは主流のソリューションではありません。少しやりすぎです。バスティオン マシンを使用すると、システムを自由に使用できないし、無料のバスティオン マシンについては聞いたこともありません。 [推奨: PHP ビデオ チュートリアル ]

それで、どうすればよいでしょうか? 上級

PHP 開発者として、サーバー アプリケーションはまだすぐに利用できません。ネットワークへの侵入は可能です。 IP フィルタリング システムを使用すると簡単に実現できますが、これは簡単なことです。そこで、このようなプロジェクトを自分で開発する予定です。まず、IP フィルタリングを実装できます。さらに、ホワイトリストに IP を簡単に追加できます。たとえば、Web にアクセスしたときなどです。ページにアクセスすると、自動的にホワイトリストに追加されます。

プロジェクト全体は数時間以内に開発されました。少なくとも私自身のニーズを満たし、次の機能を実現しました:

    マルチプロセス
  • サポート同時実行性
  • デーモンプロセス
  • Webパネルから管理可能
  • IP#トラフィック統計
  • 傍受記録
  • それでは、このシステムを段階的に実装してみましょう。

最初のステップは、単に

IP

をフィルタリングすることです。

PHP

を使用してポートをリッスンし、データを転送するためのフレームワークが多数あります。私が workerman を選んだ理由は次のとおりです 3:

シンプルで安定した動作
  • シンプルなメソッド インターフェース
  • 構築済み-in process Guard
  • 具体的なインストール方法については、公式ドキュメントを参照してください。

著作権声明: この記事はオリジナルであり、

phpreturn.com

(PHP Weapon Library 公式 Web サイト) によって公開されており、すべての権利は phpreturn に属します。 ( PHPArmory) なお、当サイトでは/引用記事の転載をいかなる形式でも許可しておりますが、同時に出典を明記する必要があります。

IP アクセス制御: PHP を使用して IP ファイアウォールを実装する方法をナニー スタイルで教えます

workerman

は使い方が非常に簡単です。10 行のコードがあれば、IP を転送できます。 ホワイトリスト フィルタリング:

$worker = new Worker('tcp:0.0.0.0:' . Config::get('door.port_in'));
// 监听一个端口
$worker->count = 2;
// 设置多进程
$worker->onConnect = function (TcpConnection $connection) {
    // 获取IP白名单
    $list_ip = AppIp::where('status', 0)->cache(3)->column('ip');
    $remote_ip = $connection->getRemoteIp();
    // 拦截IP
    if (!in_array($remote_ip, $list_ip)) {
        $connection->close();
    }
    // 放行连接,连接内部目标端口
    $to_connection = new AsyncTcpConnection('tcp:127.0.0.1:' . Config::get('door.port_to'));
    // 互相转发流量
    $connection->pipe($to_connection);
    $to_connection->pipe($connection);
    $to_connection->connect();
}
ログイン後にコピー
上記のコードに示すように、わずか数行で、

IP

の監視と転送が実現されます。 IP ホワイトリストはデータベースを通じてクエリされ、キャッシュされます。 2 番目のステップは、ThinkPHP

コマンド ラインと統合することです。

プロジェクト開発の便宜上、ThinkPHP

フレームワークを使用します。開発用途としては十分シンプルで機能も比較的充実しています。

IP アクセス制御: PHP を使用して IP ファイアウォールを実装する方法をナニー スタイルで教えます

最终实现的命令行效果如下:

版权声明:本文由phpreturn.comPHP武器库官网)原创和首发,所有权利归phpreturnPHP武器库)所有,本站允许任何形式的转载/引用文章,但必须同时注明出处。

运行命令
php think door start
php think door start --mode d  // 守护进程重启
重启
php think door restart
停止
php think door stop
ログイン後にコピー

workerman的命令参数与thinkphp并不兼容,但是实现这样的效果并不难,实际上很简单,代码如下:

<?php

declare(strict_types=1);

namespace app\common\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;

class Door extends Command
{
    protected function configure()
    {
        // 指令配置
        $this->setName(&#39;door&#39;)
            // 设置think的命令参数
            ->addArgument(&#39;action&#39;, Argument::OPTIONAL, "start|stop|restart|reload|status|connections", &#39;start&#39;)
            ->addOption(&#39;mode&#39;, &#39;m&#39;, Option::VALUE_OPTIONAL, &#39;Run the workerman server in daemon mode.&#39;)
            ->setDescription(&#39;the door command&#39;);
    }
    protected function execute(Input $input, Output $output)
    {
        // 指令输出
        $output->writeln(&#39;door&#39;);
        $action = $input->getArgument(&#39;action&#39;);
        $mode = $input->getOption(&#39;mode&#39;);
        // 重新构造命令行参数,以便兼容workerman的命令
        global $argv;
        $argv = [];
        array_unshift($argv, &#39;think&#39;, $action);
        if ($mode == &#39;d&#39;) {
            $argv[] = &#39;-d&#39;;
        } else if ($mode == &#39;g&#39;) {
            $argv[] = &#39;-g&#39;;
        }
        // ...workerman的代码
    }
}
ログイン後にコピー

在上面的代码中,主要做了两件事:

  • 实现ThinkPHP的命令设置
  • 将命令参数重新构造为workerman兼容的方式

第三步,实现管理面板

使用PHP实现一个管理面板太简单了,PHP到处都是这样的后台框架,这里我选择ulthon_admin,这是我自己开发维护的,它基于ThinkPHP6,很简单,为定制而生,不搞所谓的“插件”和“市场”生态,能够自动生成CURD代码,并且内置几了几个有趣的皮肤。

最终效果如下:

IP アクセス制御: PHP を使用して IP ファイアウォールを実装する方法をナニー スタイルで教えますIP アクセス制御: PHP を使用して IP ファイアウォールを実装する方法をナニー スタイルで教えます

以上是ulthon_admin内置的两款皮肤效果,分别是:科幻、像素。

对于面板的管理,这里多做介绍,这算是PHP开发者的基本功,谁还不会个CURD啊。

版权声明:本文由phpreturn.comPHP武器库官网)原创和首发,所有权利归phpreturnPHP武器库)所有,本站允许任何形式的转载/引用文章,但必须同时注明出处。

第四步,进阶,更好的性能和流量统计

我们的IP拦截客户端需要运行在服务器上,并且直接连接数据库,如果每次收到请求都要查询数据库,那么很有可能导致连接不通畅,尤其是客户端和数据库本身位置较远的时候。在第一步的代码中,我们只是简单的使用了查询缓存,但是还不够,还可以优化。并且我们可以在管理面板的截图中看到,我们是可以统计流量和拦截次数的,现在我们要实现这些功能:

流量统计

首先我们将第一个步中,流量转发部分的代码改造成如下的样子:

<?php
// 向TO发起连接
$to_connection = new AsyncTcpConnection(&#39;tcp://127.0.0.1:&#39; . Config::get(&#39;door.port_to&#39;));
$to_connection->onMessage = function ($source, $data) use ($connection, $remote_ip) {
    // 接收到来自TO的数据,返回的数据
    $connection->send($data);
    // 将流量统计存储到内存里
    Cache::inc(md5($remote_ip) . &#39;-to&#39;, strlen($data));
};
// 流程和流量控制
$to_connection->onClose = function ($source) use ($connection) {
    $connection->close();
};
$connection->onBufferFull = function ($dest) use ($to_connection) {
    $to_connection->pauseRecv();
};
$connection->onBufferDrain = function ($dest) use ($to_connection) {
    $to_connection->resumeRecv();
};
$connection->onMessage = function ($source, $data) use ($to_connection, $remote_ip) {
    // 接收来自IN的数据,请求的数据
    $to_connection->send($data);
    // 将流量统计存储到内存里
    Cache::inc(md5($remote_ip) . &#39;-in&#39;, strlen($data));
};
// 流程和流量控制
$connection->onClose = function ($source) use ($to_connection) {
    $to_connection->close();
};
$to_connection->onBufferFull = function ($dest) use ($connection) {
    $connection->pauseRecv();
};
$to_connection->onBufferDrain = function ($dest) use ($connection) {
    $connection->resumeRecv();
};
ログイン後にコピー

在第一部的代码中,只用两行便实现了这些代码:

// 放行连接,连接内部目标端口
$to_connection = new AsyncTcpConnection(&#39;tcp:127.0.0.1:&#39; . Config::get(&#39;door.port_to&#39;));
// 互相转发流量
$connection->pipe($to_connection);
$to_connection->pipe($connection);
ログイン後にコピー

这里使用的是workerman内置的流量转发,它很好用,但是这里我们要统计流量,所以我们手动转发流量。

这里我们将统计的数据存储到缓存里,而不是直接连接数据库更新,这是为了更好的连接性能。我们会另外开启一个进程将这些改动更新到数据库。后面会介绍到。

拦截统计

我们将第一步中的加载IP白名单的逻辑改成下面这样:

版权声明:本文由phpreturn.comPHP武器库官网)原创和首发,所有权利归phpreturnPHP武器库)所有,本站允许任何形式的转载/引用文章,但必须同时注明出处。

<?php
$worker->onConnect = function (TcpConnection $connection) {
    $disable_cache_key = &#39;disable_ip_list&#39;;
    $list_ip = Cache::get($disable_cache_key);
    if (empty($list_ip)) {
        $connection->close();
    }
    $remote_ip = $connection->getRemoteIp();
    if (!in_array($remote_ip, $list_ip)) {
        AppIpReject::initRecord($remote_ip);
        $connection->close();
    }
};
ログイン後にコピー

在这里我们不连接数据库查询,而是直接从本地缓存读取白名单,这样会有更好的性能。我们会在另一个进程中更新这份白名单。

另外我们可以看到,拦截的IP调用了一个静态方法,这里的功能很简单,判断数据库中该IP是否存在,如果不存在则新增,如果存在,则更新拦截次数+·1。这里就不多介绍了。这里也没有必要做什么性能优化,反正本来就是拦截的IP,优化个毛。

高性能处理缓存数据

上面我们介绍,我们会另外开启一个进程,维护IP白名单,并且将流量统计提交到数据库。这就是这个进程:

<?php
$worker_ip = new Worker();
$worker_ip->name = &#39;report&#39;;
$worker_ip->onWorkerStart = function () {
    Timer::add(5, function () {
        $disable_cache_key = &#39;disable_ip_list&#39;;
        $list_ip = AppIp::where(&#39;status&#39;, 1)->column(&#39;ip&#39;);
        Cache::set($disable_cache_key, $list_ip);
        foreach ($list_ip as  $ip) {
            $ip_md5 = md5($ip);
            $in_length = Cache::pull("$ip_md5-in");
            // 请求的数据
            $to_length = Cache::pull("$ip_md5-to");
            // 返回的数据
            if (!empty($in_length) || !empty($to_length)) {
                $model_ip = AppIp::where(&#39;ip&#39;, $ip)->find();
                $model_ip->in_buffer += $in_length;
                $model_ip->to_buffer += $to_length;
                $model_ip->save();
            }
        }
    });
};
ログイン後にコピー

他做的事情很简单,读取缓存,更新数据到数据库,并且更新IP白名单。这里不需要考虑它和数据库之间的性能问题,这是额外的进程,不影响端口的连接和转发。

下一步,更好的性能设计

以上,只有几行代码,几个小时(如果不含设计系统的时间,代码量可能只有一两个小时。还能再怎么优化呢?实际上还是可以优化的。

更好的内存驱动

这里使用的是ThinkPHP内置的文件缓存,存储到磁盘上,以上方法,在大量连接并发时,肯定受制于磁盘的性能。所以自然而然,我们可以使用内存缓存。

版权声明:本文由phpreturn.comPHP武器库官网)原创和首发,所有权利归phpreturnPHP武器库)所有,本站允许任何形式的转载/引用文章,但必须同时注明出处。

但是使用内存缓存,redis可以吗?并不好。这里是客户端,它只是想简简单单实现一个拦截转发,还要再部署redis,不可取。

但实际上,workerman本身内置了数据共享组件,这是一个很好的方案。相当于一个极简的redis。完美符合我们的需求。但是我并没有实现这个功能,目前的系统已经符合我的场景。

更好的客户端

目前拦截IP客户端和管理面板集成在一起,使用相同的配置,面板基于ThinkPHP,客户端只是ThinkPHP的一个命令。我之所以这样做,是希望直接在Workerman中使用ThinkPHP的众多特性(数据库、缓存

实际上,我们可以将客户端的代码,另外开一个项目,使客户端和面板独立开。在面板上实现通用得API。客户端通过API操作数据。这样客户端就不需要连接数据库。好处多多。

ただし、負荷も大きくなりますので、この場合は当然クライアント環境が安全ではないと考えられるため、権限認証やログイン認証を行う必要があります。インターフェイスの開発には、より多くのコードを記述する必要もあります。

概要

この記事では主に、IP ファイアウォールを実装するための私のアイデアを紹介します。これらの技術では、開発者に豊富な Web サイト開発経験が求められますが、この要件はそれほど高くはありませんが、基本的なネットワーク開発経験も必要であり、一定の基準があります。 Workerman は非常にシンプルですが、WorkermanHTTP ではありません。これは通常の Web サイト開発ではないため、一定の学習と考え方の変更が必要です。しかし、私にとっては、気楽に運転するのが簡単です。学習、展開、テストするための他のソリューションを探す場合、自分で開発するよりも早くない可能性があります。

著作権声明: この記事はオリジナルであり、phpreturn.com (PHP Weapon Library 公式 Web サイト) によって公開されており、すべての権利は phpreturn に属します。 ( PHPArmory) なお、当サイトでは/引用記事の転載をいかなる形式でも許可しておりますが、同時に出典を明記する必要があります。

IPホワイトリストを管理するにはどうすればよいですか? パネルからホワイトリストを追加するか、パネルのページにアクセスしてアウトバウンド IP を自動的に取得し、それをホワイトリスト、ユーザーエクスペリエンスは非常に優れています。

実際には、より良い方法があります。それは、rss サーバーを作成し、rss# を購読している顧客の送信ネットワーク IP## を自動的に取得することです。 ホワイトリストに追加します。しかし、私には rss を使用する習慣がありません。また、携帯電話には優れた rss リーダーが搭載されておらず、毎回それを開きたくありません。 IP ホワイトリストを更新します。このソリューションは使用しません。

これをオープンソースにしました。必要な場合は、https://gitee.com/augushong/ip-door を参照してください。

詳細

このシステムは、

iptables と比較して、より便利な IP ホワイトリスト管理エクスペリエンスを備えており、シンプルな要塞マシンと同等です。 。彼はいくつかのポートを非表示にして、「私」だけが接続できるようにすることができます。

たとえば、

ssh のポートを非表示にし、ip アクセス制御を通じて転送します。別の例は、80 ポートを非表示にし、ip アクセス制御を通じて転送することです。

現在のところ、私のシステムは複数のポートの同時バインドと転送を実装していませんが、中心的な考え方は同じであり、参考として使用できます。

著作権声明: この記事はオリジナルであり、

phpreturn.com (PHP Weapon Library 公式 Web サイト) によって公開されており、すべての権利は phpreturn に属します。 ( PHPArmory) なお、当サイトでは/引用記事の転載をいかなる形式でも許可しておりますが、同時に出典を明記する必要があります。

以上がIP アクセス制御: PHP を使用して IP ファイアウォールを実装する方法をナニー スタイルで教えますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
php
ソース:phpreturn.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!