最近我遇到一个需求,我的一台服务器总是遭到端口扫描和恶意登录攻击,对此可以怎么办呢?似乎除了内网隔离、增强密码认证、证书登录、设置防火墙
这些方案实际上都无法解决我的问题。这是一台公网服务器,并没有什么复杂的网络结构,所以不能建立内网隔离。调整账号的密码策略,自然是一个方案,但是人工操作太麻烦,而且我一般经常换电脑使用,如果修改密码,公司的和家里的电脑都要更新,很麻烦。设置防火墙自然是运维的基本操作,但是
那怎么办呢,作为一个资深的
(资料图)
整个项目不到几个小时就研发完了,起码满足了我自己的需求,并且实现了这样几个特性:
多进程支持并发守护进程可以通过网页面板管理现在我们来一步一步的实现这个系统。
第一步,首先能够简简单单的过滤IP
使用
至于具体的安装方法,可以参考他的官方文档。
版权声明:本文由phpreturn.com(
$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();}
正如上面代码所示,只有简单几行,便实现了
第二步,与ThinkPHP 命令行整合在一起
为了项目开发方便,我都会使用
最终实现的命令行效果如下:
版权声明:本文由phpreturn.com(
运行命令php think door startphp think door start --mode d // 守护进程重启重启php think door restart停止php think door stop
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的代码 }}
在上面的代码中,主要做了两件事:
实现第三步,实现管理面板
使用
最终效果如下:
以上是
对于面板的管理,这里多做介绍,这算是
版权声明:本文由phpreturn.com(
第四步,进阶,更好的性能和流量统计
我们的
流量统计
首先我们将第一个步中,流量转发部分的代码改造成如下的样子:
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);
这里使用的是
这里我们将统计的数据存储到缓存里,而不是直接连接数据库更新,这是为了更好的连接性能。我们会另外开启一个进程将这些改动更新到数据库。后面会介绍到。
拦截统计
我们将第一步中的加载
版权声明:本文由phpreturn.com(
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(); }};
在这里我们不连接数据库查询,而是直接从本地缓存读取白名单,这样会有更好的性能。我们会在另一个进程中更新这份白名单。
另外我们可以看到,拦截的
高性能处理缓存数据
上面我们介绍,我们会另外开启一个进程,维护
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(); } } });};
他做的事情很简单,读取缓存,更新数据到数据库,并且更新
下一步,更好的性能设计
以上,只有几行代码,几个小时(如果不含设计系统的时间,代码量可能只有一两个小时
更好的内存驱动
这里使用的是
版权声明:本文由phpreturn.com(
但是使用内存缓存,
但实际上,
更好的客户端
目前拦截
实际上,我们可以将客户端的代码,另外开一个项目,使客户端和面板独立开。在面板上实现通用得
但是这样也带来的更多的工作量,这种情况下,我们自然而然的认为客户端的环境不安全,所以要做权限认证,登录认证。接口开发也要写更多的代码。
总结
这篇文章主要介绍了我实现
版权声明:本文由phpreturn.com(
实际上还有更好的方式,那就是做一个
我把它开源了,如果有需要可以参考: https://gitee.com/augushong/ip-door 。
更多
这个系统,跟
比如将
目前我的系统还没有实现多个端口的同时绑定转发,但是核心的思路是一样的,可以参考使用。
版权声明:本文由phpreturn.com(
本文系转载,原文标题:
IP 门禁:手把手教你用PHP 实现一个IP 防火墙原文地址:https://phpreturn.com/index/a62e1ddd672933.html
原文平台:
PHP 武器库
以上就是IP门禁:保姆式教你用PHP实现一个IP防火墙的详细内容,更多请关注php中文网其它相关文章!