최근에 요구 사항이 발생했습니다. 내 서버 중 하나가 항상 포트 스캐닝 및 악의적인 로그인 공격을 받기 쉽습니다. 인트라넷 격리, 강화된 비밀번호 인증, 인증서 로그인, 방화벽
이러한 솔루션 중 어느 것도 실제로 내 문제를 해결하지 못합니다. 공용 네트워크 서버로 복잡한 네트워크 구조를 갖고 있지 않아 인트라넷 격리가 불가능합니다. 계정의 비밀번호 정책을 조정하는 것이 당연히 해결 방법이지만, 수동 조작이 너무 번거롭고, 컴퓨터를 바꾸는 경우가 많습니다. 비밀번호를 변경하면 회사 컴퓨터와 집 컴퓨터를 모두 업데이트해야 하므로 매우 번거롭습니다. 방화벽 설정은 당연히 운영과 유지관리를 위한 기본 작업이지만
PHP
- 다중 프로세스
- 동시성 지원
- 데몬 프로세스
- 웹 패널을 통해 관리 가능
- IP
- 차단 기록
IP
포트를 수신하고 데이터를 전달하기 위해 PHP
- 쉬움 Run Stable
- 간단한 메소드 인터페이스
- 내장 프로세스 데몬
workerman
$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
ThinkPHP명령줄
과 통합하는 것입니다. 프로젝트 개발의 편의를 위해 ThinkPHP
最终实现的命令行效果如下:
版权声明:本文由phpreturn.com(
运行命令 php think door start php think door start --mode d // 守护进程重启 重启 php think door restart 停止 php think door stop
<?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('door') // 设置think的命令参数 ->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'); // 重新构造命令行参数,以便兼容workerman的命令 global $argv; $argv = []; array_unshift($argv, 'think', $action); if ($mode == 'd') { $argv[] = '-d'; } else if ($mode == 'g') { $argv[] = '-g'; } // ...workerman的代码 } }
在上面的代码中,主要做了两件事:
- 实现
ThinkPHP 的命令设置 - 将命令参数重新构造为
workerman 兼容的方式
第三步,实现管理面板
使用
最终效果如下:
以上是
对于面板的管理,这里多做介绍,这算是
版权声明:本文由phpreturn.com(
第四步,进阶,更好的性能和流量统计
我们的
流量统计
首先我们将第一个步中,流量转发部分的代码改造成如下的样子:
<?php // 向TO发起连接 $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的数据,返回的数据 $connection->send($data); // 将流量统计存储到内存里 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的数据,请求的数据 $to_connection->send($data); // 将流量统计存储到内存里 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(); };
在第一部的代码中,只用两行便实现了这些代码:
// 放行连接,连接内部目标端口 $to_connection = new AsyncTcpConnection('tcp:127.0.0.1:' . Config::get('door.port_to')); // 互相转发流量 $connection->pipe($to_connection); $to_connection->pipe($connection);
这里使用的是
这里我们将统计的数据存储到缓存里,而不是直接连接数据库更新,这是为了更好的连接性能。我们会另外开启一个进程将这些改动更新到数据库。后面会介绍到。
拦截统计
我们将第一步中的加载
<?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(); } };
在这里我们不连接数据库查询,而是直接从本地缓存读取白名单,这样会有更好的性能。我们会在另一个进程中更新这份白名单。
另外我们可以看到,拦截的
高性能处理缓存数据
上面我们介绍,我们会另外开启一个进程,维护
<?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"); // 请求的数据 $to_length = Cache::pull("$ip_md5-to"); // 返回的数据 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(); } } }); };
他做的事情很简单,读取缓存,更新数据到数据库,并且更新
下一步,更好的性能设计
以上,只有几行代码,几个小时(如果不含设计系统的时间,代码量可能只有一两个小时
更好的内存驱动
这里使用的是
但是使用内存缓存,
但实际上,
更好的客户端
目前拦截
实际上,我们可以将客户端的代码,另外开一个项目,使客户端和面板独立开。在面板上实现通用得
하지만 이 경우에는 당연히 클라이언트 환경이 안전하지 않다고 생각하기 때문에 권한 인증과 로그인 인증을 수행해야 합니다. 인터페이스를 개발하려면 더 많은 코드를 작성해야 합니다.
요약
이 글은 주로
사실 더 좋은 방법이 있는데,
오픈소스로 만들었습니다. 필요하신 분은 https://gitee.com/augushong/ip-door를 참고해주세요.
More
예를 들어
현재 내 시스템은 여러 포트의 동시 바인딩 및 전달을 구현하지 않았지만 핵심 아이디어는 동일하며 참조로 사용할 수 있습니다.
이 기사는 재인쇄되었습니다. 원본 제목:
IP 액세스 제어:PHP 를 사용하여IP 방화벽을 구현하는 방법을 단계별로 설명합니다. 원본 주소: https://phpreturn.com/index /a62e1ddd672933.html