日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

最近我遇到一個需求,我的一臺服務器總是遭到端口掃描和惡意登錄攻擊,對此可以怎么辦呢?似乎除了內(nèi)網(wǎng)隔離、增強密碼認證、證書登錄、設置防火墻iptables,網(wǎng)上找不到什么別的方案,對了,還用堡壘機的方案。

這些方案實際上都無法解決我的問題。這是一臺公網(wǎng)服務器,并沒有什么復雜的網(wǎng)絡結構,所以不能建立內(nèi)網(wǎng)隔離。調(diào)整賬號的密碼策略,自然是一個方案,但是人工操作太麻煩,而且我一般經(jīng)常換電腦使用,如果修改密碼,公司的和家里的電腦都要更新,很麻煩。設置防火墻自然是運維的基本操作,但是iptables的配置太麻煩,ufw工具還好些,firewall-cmd就麻煩些,而且有一個巨大的痛點,眾所周知,大家的出網(wǎng)IP都會經(jīng)常變,好不容易在命令行里一個字母一個字母的配置好了,睡了一覺,白費了。堡壘機更不是一個主流的方案,有點大材小用,用了堡壘機,反而不能隨意使用系統(tǒng),更何況還沒聽說過那個免費的堡壘機呢。

那怎么辦呢,作為一個資深的php開發(fā)者,服務器這塊的應用還不是手到擒來,當初連內(nèi)網(wǎng)穿透都能輕松實現(xiàn),一個IP過濾系統(tǒng),小意思。所以我打算自己開發(fā)這樣一個項目,首先能夠實現(xiàn)IP過濾,另外,可以輕松地將IP加入到白名單里,比如訪問一個網(wǎng)頁,就自動加入到白名單。

整個項目不到幾個小時就研發(fā)完了,起碼滿足了我自己的需求,并且實現(xiàn)了這樣幾個特性:

  • 多進程
  • 支持并發(fā)
  • 守護進程
  • 可以通過網(wǎng)頁面板管理IP
  • 流量統(tǒng)計
  • 攔截記錄

現(xiàn)在我們來一步一步地實現(xiàn)這個系統(tǒng)。

第一步,首先能夠簡簡單單的過濾IP

使用PHP監(jiān)聽端口并且轉發(fā)數(shù)據(jù)的框架很多,對此我選擇workerman,原因有3:

  • 運行簡單穩(wěn)定
  • 方法接口簡單
  • 內(nèi)置進程守護

至于具體的安裝方法,可以參考他的官方文檔。

 

workerman的使用方法非常簡單,只要10行代碼,就實現(xiàn)了IP轉發(fā)+白名單過濾:

$worker = new Worker('tcp:0.0.0.0:' . Config::get('door.port_in'));// 監(jiān)聽一個端口$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();    }    // 放行連接,連接內(nèi)部目標端口    $to_connection = new AsyncTcpConnection('tcp:127.0.0.1:' . Config::get('door.port_to'));    // 互相轉發(fā)流量    $connection->pipe($to_connection);    $to_connection->pipe($connection);    $to_connection->connect();}

正如上面代碼所示,只有簡單幾行,便實現(xiàn)了IP監(jiān)聽和轉發(fā),其中IP白名單通過數(shù)據(jù)庫查詢,并且緩存。

第二步,與ThinkPHP命令行整合在一起

為了項目開發(fā)方便,我都會使用ThinkPHP框架進行開發(fā),它夠簡單,功能也比較齊全。

 

最終實現(xiàn)的命令行效果如下:

運行命令php think door start php think door start --mode d  // 守護進程重啟重啟php think door restart停止php think door stop

workerman的命令參數(shù)與thinkphp并不兼容,但是實現(xiàn)這樣的效果并不難,實際上很簡單,代碼如下:

<?phpdeclare(strict_types=1);namespace appcommoncommand;use thinkconsoleCommand;use thinkconsoleInput;use thinkconsoleinputArgument;use thinkconsoleinputOption;use thinkconsoleOutput;class Door extends Command{    protected function configure()    {        // 指令配置        $this->setName('door')            // 設置think的命令參數(shù)            ->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload|status|connections", 'start')            ->addOption('mode', 'm', Option::VALUE_OPTIONAL, 'Run the workerman server in daemon mode.')            ->setDescription('the door command');    }    protected function execute(Input $input, Output $output)    {        // 指令輸出        $output->writeln('door');        $action = $input->getArgument('action');        $mode = $input->getOption('mode');        // 重新構造命令行參數(shù),以便兼容workerman的命令        global $argv;        $argv = [];        array_unshift($argv, 'think', $action);        if ($mode == 'd') {            $argv[] = '-d';        } else if ($mode == 'g') {            $argv[] = '-g';        }        // ...workerman的代碼    }}

在上面的代碼中,主要做了兩件事:

  • 實現(xiàn)ThinkPHP的命令設置
  • 將命令參數(shù)重新構造為workerman兼容的方式

第三步,實現(xiàn)管理面板

使用PHP實現(xiàn)一個管理面板太簡單了,PHP到處都是這樣的后臺框架,這里我選擇ulthon_admin,這是我自己開發(fā)維護的,它基于ThinkPHP6,很簡單,為定制而生,不搞所謂的“插件”和“市場”生態(tài),能夠自動生成CURD代碼,并且內(nèi)置幾了幾個有趣的皮膚。

最終效果如下:

 


 

以上是ulthon_admin內(nèi)置的兩款皮膚效果,分別是:科幻、像素。

對于面板的管理,這里多做介紹,這算是PHP開發(fā)者的基本功,誰還不會個CURD啊。

第四步,進階,更好的性能和流量統(tǒng)計

我們的IP攔截客戶端需要運行在服務器上,并且直接連接數(shù)據(jù)庫,如果每次收到請求都要查詢數(shù)據(jù)庫,那么很有可能導致連接不通暢,尤其是客戶端和數(shù)據(jù)庫本身位置較遠的時候。在第一步的代碼中,我們只是簡單地使用了查詢緩存,但是還不夠,還可以優(yōu)化。并且我們可以在管理面板的截圖中看到,我們是可以統(tǒng)計流量和攔截次數(shù)的,現(xiàn)在我們要實現(xiàn)這些功能:

流量統(tǒng)計

首先我們將第一個步驟,流量轉發(fā)部分的代碼改造成如下的樣子:

<?php// 向TO發(fā)起連接$to_connection = new AsyncTcpConnection('tcp://127.0.0.1:' . Config::get('door.port_to'));$to_connection->onMessage = function ($source, $data) use ($connection, $remote_ip) {    // 接收到來自TO的數(shù)據(jù),返回的數(shù)據(jù)    $connection->send($data);    // 將流量統(tǒng)計存儲到內(nèi)存里    Cache::inc(md5($remote_ip) . '-to', 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的數(shù)據(jù),請求的數(shù)據(jù)    $to_connection->send($data);    // 將流量統(tǒng)計存儲到內(nèi)存里    Cache::inc(md5($remote_ip) . '-in', 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();};

在第一部的代碼中,只用兩行便實現(xiàn)了這些代碼:

// 放行連接,連接內(nèi)部目標端口$to_connection = new AsyncTcpConnection('tcp:127.0.0.1:' . Config::get('door.port_to'));// 互相轉發(fā)流量$connection->pipe($to_connection);$to_connection->pipe($connection);

這里使用的是workerman內(nèi)置的流量轉發(fā),它很好用,但是這里我們要統(tǒng)計流量,所以我們手動轉發(fā)流量。

這里我們將統(tǒng)計的數(shù)據(jù)存儲到緩存里,而不是直接連接數(shù)據(jù)庫更新,這是為了更好的連接性能。我們會另外開啟一個進程將這些改動更新到數(shù)據(jù)庫。后面會介紹到。

攔截統(tǒng)計

我們將第一步中的加載IP白名單的邏輯改成下面這樣:

<?php$worker->onConnect = function (TcpConnection $connection) {    $disable_cache_key = 'disable_ip_list';    $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();    }};

在這里我們不連接數(shù)據(jù)庫查詢,而是直接從本地緩存讀取白名單,這樣會有更好的性能。我們會在另一個進程中更新這份白名單。

另外我們可以看到,攔截的IP調(diào)用了一個靜態(tài)方法,這里的功能很簡單,判斷數(shù)據(jù)庫中該IP是否存在,如果不存在則新增,如果存在,則更新攔截次數(shù)+·1。這里就不多介紹了。這里也沒有必要做什么性能優(yōu)化,反正本來就是攔截的IP,優(yōu)化個毛。

高性能處理緩存數(shù)據(jù)

上面我們介紹,我們會另外開啟一個進程,維護IP白名單,并且將流量統(tǒng)計提交到數(shù)據(jù)庫。這就是這個進程:

<?php$worker_ip = new Worker();$worker_ip->name = 'report';$worker_ip->onWorkerStart = function () {    Timer::add(5, function () {        $disable_cache_key = 'disable_ip_list';        $list_ip = AppIp::where('status', 1)->column('ip');        Cache::set($disable_cache_key, $list_ip);        foreach ($list_ip as  $ip) {            $ip_md5 = md5($ip);            $in_length = Cache::pull("$ip_md5-in");            // 請求的數(shù)據(jù)            $to_length = Cache::pull("$ip_md5-to");            // 返回的數(shù)據(jù)            if (!empty($in_length) || !empty($to_length)) {                $model_ip = AppIp::where('ip', $ip)->find();                $model_ip->in_buffer += $in_length;                $model_ip->to_buffer += $to_length;                $model_ip->save();            }        }    });};

他做的事情很簡單,讀取緩存,更新數(shù)據(jù)到數(shù)據(jù)庫,并且更新IP白名單。這里不需要考慮它和數(shù)據(jù)庫之間的性能問題,這是額外的進程,不影響端口的連接和轉發(fā)。

下一步,更好的性能設計

以上,只有幾行代碼,幾個小時(如果不含設計系統(tǒng)的時間,代碼量可能只有一兩個小時)。還能再怎么優(yōu)化呢?實際上還是可以優(yōu)化的。

更好的內(nèi)存驅動

這里使用的是ThinkPHP內(nèi)置的文件緩存,存儲到磁盤上,以上方法,在大量連接并發(fā)時,肯定受制于磁盤的性能。所以自然而然,我們可以使用內(nèi)存緩存。

但是使用內(nèi)存緩存,redis可以嗎?并不好。這里是客戶端,它只是想簡簡單單實現(xiàn)一個攔截轉發(fā),還要再部署redis,不可取。

但實際上,workerman本身內(nèi)置了數(shù)據(jù)共享組件,這是一個很好的方案。相當于一個極簡的redis。完美符合我們的需求。但是我并沒有實現(xiàn)這個功能,目前的系統(tǒng)已經(jīng)符合我的場景。

更好的客戶端

目前攔截IP客戶端和管理面板集成在一起,使用相同的配置,面板基于ThinkPHP,客戶端只是ThinkPHP的一個命令。我之所以這樣做,是希望直接在Workerman中使用ThinkPHP的眾多特性(數(shù)據(jù)庫、緩存)。

實際上,我們可以將客戶端的代碼,另外開一個項目,使客戶端和面板獨立開。在面板上實現(xiàn)通用得API??蛻舳送ㄟ^API操作數(shù)據(jù)。這樣客戶端就不需要連接數(shù)據(jù)庫。好處多多。

但是這樣也帶來的更多的工作量,這種情況下,我們自然而然的認為客戶端的環(huán)境不安全,所以要做權限認證,登錄認證。接口開發(fā)也要寫更多的代碼。

總結

這篇文章主要介紹了我實現(xiàn)IP防火墻的思路。這些技術,需要開發(fā)者有豐富的網(wǎng)站開發(fā)經(jīng)驗,這個要求不高,但是也要有基本的網(wǎng)絡開發(fā)經(jīng)驗,這就有一定的門檻。Workerman非常簡單,但是Workerman不是HTTP,這不是一般的網(wǎng)站開發(fā),需要一定的學習和思路轉變。但是對于我來說,輕車駕熟。如果我去找其他的方案,學習、部署、測試,可能還不如我自己開發(fā)來更快。

IP白名單是怎么管理的呢,既可以通過面板添加,也可以訪問面板的一個頁面,自動獲取出網(wǎng)IP添加到白名單中,使用體驗和很好。

實際上還有更好的方式,那就是做一個rss服務器,自動獲取訂閱rss的客戶單的出網(wǎng)IP加入到白名單。但是我本身沒有使用rss的習慣,并且手機上也沒有好的rss閱讀器,也不想每次更新IP白名單都要特意打開它,也就沒使用這個方案。

我把它開源了,如果有需要可以參考:
https://gitee.com/augushong/ip-door

更多

這個系統(tǒng),跟iptables相比,只是有一個更方便的IP白名單管理體驗而已,相當于一個簡單堡壘機。他可以實現(xiàn),將一些端口隱藏起來,只有“我”能連接。

比如將ssh的端口隱藏起來,通過ip門禁轉發(fā)過去。再比如將80端口隱藏起來,通過ip門禁轉發(fā)過去。

目前我的系統(tǒng)還沒有實現(xiàn)多個端口的同時綁定轉發(fā),但是核心的思路是一樣的,可以參考使用。

 

原文標題:IP門禁:手把手教你用PHP實現(xiàn)一個IP防火墻

原文地址:
https://phpreturn.com/index/a62e1ddd672933.html

原文平臺:PHP武器庫

版權聲明:本文由phpreturn.com(PHP武器庫官網(wǎng))原創(chuàng)和首發(fā),所有權利歸phpreturn(PHP武器庫)所有,本站允許任何形式的轉載/引用文章,但必須同時注明出處。

分享到:
標簽:防火墻 IP
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定