由于typecho是动态的博客系统,因此单纯的使用GET请求博客动态内容都能对网站造成非常大的负载压力。

注意:这篇文章只是用来防御脚本小子的F5攻击,实际防御能力有限,无法防御刷流量,无法防御大佬的攻击。做站千万别惹大佬,犯错了及时认怂才是王道。

每个人做站的环境不同,我是使用APPNODE来做网站的,请根据你自己实际的情况进行处理。

如果是需要防御dd源站ip,可以看这篇博客,有少许的效果。

原理

typecho由于是动态博客,单纯的搜索接口甚至刷新页面,都需要服务器的CPU进行处理,因此即使套上了CDN也防御不了CC。也就是站长们常说的F5都能打死网站。

因此,就需要从软件和硬件两个方面入手:提高服务器的负载能力(堆硬件)以及配置nginx/apache/MySQL的策略。

以下的策略参数均为最适合我自己的服务器的参数,并且我还在不断调试。请根据你自己的服务器情况来进行配置,而不是直接复制粘贴。

操作流程

站库分离

通过分离网站后端与数据库,减少服务器在高负载情况下CPU与内存的消耗,防止出现服务器在高负荷情况下连web软件都挂掉/ssh都进不去的尴尬情况。

博客搬迁,分离站库的过程:

简单的来讲就是把博客和图床的数据库地址指向数据库服务器内网ip,数据库服务器修改配置,仅对博客数据库开放ip,加上阿里云账户直接内网不通策略,其实还算安全。

阿里云的北京学生机内网带宽只有0.5G,平常够用,但在被C请求过程中,内网带宽成了瓶颈之一。

趁着阿里云给大学生的活动才能弄到第二台服务器,平常我可买不起。

其实最优解是购买阿里云/腾讯云的云数据库,但我没钱,并且云数据库对并发限制的非常死。
因此我使用的是:一台服务器作为网站后台服务器,一台服务器单纯作为数据库服务器。

土豪大佬直接购买的时候请注意要用ECS,阿里云轻量服务器没法通过阿里云内网互相连接。

(假)负载均衡

我这有从同学那蹭来了两台活动服务器,和我博客网站后台服务器和数据库服务器都在阿里云北京地区,虽然都是1Mb的带宽,但通过(假)负载均衡,最大可以拥有4Mb的出口带宽。

大致流程就是,同学的两台活动服务器加上数据库的服务器通过阿里云CEN,在内网反向代理网站服务器,再在cdn处的回源ip处填这四台服务器的ip。(你也可以平常选择使用两台服务器,另外两台作为热备份)

配置数据库

我是用的APPNODE,它的数据库管理功能有个优化建议,我是按照这个来处理MySQL的参数的。
需要注意的是,为了处理海量数据,如果你的服务器数据库性能还不错的话,最大连接数max_connections请调到最大:16384

配置nginx与PHP

我用的是APPNODE,它只有nginx,因此我这里只讲在appnode上配置nginx的参数。

为了增加nginx对动态请求并发处理能力,我们需要配置以下两个地方。
进入APPNODE - 网站设置

  1. 优化 - 连接优化 - 保持连接请求数限制(10000次)
  2. PHP - PHP进程 - 按如下配置

php-process.png

其实我也不太清楚最好的配置参数,我也是根据我博客实际运行情况尽可能调大。

配置完成后,请重启php与nginx,使用网站上的配置检测,检查自己的配置是否有误。

真实IP识别

反向代理服务器 IP里面填入127.0.0.1与CDN的回源ip/ip段即可。

真实 IP 识别来源使用X-Forwarded-For,腾讯云CDN与cloudflare默认都使用这个传递用户ip。其他cdn不清楚。

配置完成后使用网站上的配置检测,检查自己的配置是否有误。
我之前弄了半天都不能用,结果测试了半天才发现是在ip段后面多了个空格

请不要填入0.0.0.0/0这种自欺欺人的方法来实现真实ip识别。腾讯云CDN使用了访客来源ip来制作X-Forwarded-For,而不是直接传递用户提供的X-Forwarded-For,因此一般不会被欺骗。

配置nginx防火墙

CC攻击防护

其实就是ngx_lua模块,在宝塔里叫nginx防火墙,在appnode里是网站设置 - 安全

我的网站接了CDN,因此就不打开CC攻击防护了。appnode的官方也建议不要使用。

在CDN后面打开CC攻击防护,CDN会缓存验证页面验证,从而影响正常用户访问。
并且由于appnode的CC攻击防护验证原理:

在收到 HTTP 请求时,CC 防护模块会拦截请求,并返回验证串,让客户端保存在 Cookie 中。 如果客户端是真实浏览器,就会在
Cookie 中保存这串验证串。 在下次请求网站时,浏览器会自动将 Cookie 中的验证串通过 HTTP 请求头部发送给网站,CC
防护模块检查验证串是否合法,合法则通行,不合法则重新拦截请求,要求重新保存验证串。
如果客户端请求网站时,一直未能提供验证串,则将被列入受限名单。

会导致typecho+handsome无法评论(其他主题/博客我没测试过因此不清楚)

因此我在平常还是关闭吧,除非在特殊情况,我才会打开这个功能。

关于为什么不像宝塔那样使用真实ip识别后限制ip频率
大佬的回复是:

CC防御不是简单地把请求频率限制下就完事了…… 通常的CC攻击都使用大量IP来进行,光是限制IP请求频率没有任何意义。

因此,appnode的选择是:测试客户端是脚本还是真浏览器。而不单纯的对ip限流。

随意拉黑ip其实毫无效果,因为真正的CC攻击甚至会用上万的ip来进行攻击。


更新:
appnode的CC防御从302跳转更新到307跳转了,现在打开了也可以评论了,因此我常开了。
但实际体验测试下发现效果不是很好,测试的时候只封了2个ip,聊有胜无吧

反代攻击防护

原理:

反代攻击,是指利用类似 Nginx
的反向代理功能,实现反向代理到您的网站,并通过字符串替换将您的网站信息进行修改,从而达到盗版/复制您的网站的目的。 该防护功能针对 GET
请求进行检测,将对所有请求强制启用压缩,使反代软件无法正常工作。

由于反代攻击防护会强行压缩JS文件导致我的图床和博客的Dplayer挂掉,因此我选择关闭。

并发与请求限制

打开博客的并发限制请求限制
位置在:网站设置 - 安全
启用整站并发限制,启用单IP并发限制,启用IP请求限制,启用整站请求限制

由于我不清楚我博客具体情况,因此我选择了默认配置,实际上默认配置完全足够。

图床请不要打开/根据你的情况尽可能调大。我实测图床打开后无法正常工作。因此我图床的并发防御交给CDN了,反正主要用到的是静态资源。

(真)负载均衡

我不会做动态网站的负载均衡,四台服务器也不需要这个。

静态网站还好,动态网站配置(真)负载均衡的话需要配置redis,貌似很麻烦的样子(主要是怕后面迁移博客太麻烦了)。

好像有那种通过docker实现单台服务器的负载均衡,以后有机会在其他网站测试。

配置系统

在测试过程中,出现了Too Many Open Files,其原因是Linux / Unix 设置了软硬文件句柄和打开文件的数目限制。
too-many-open-files.png

因此,我在appnode - 系统信息 - 系统配置 设置了
最大监控文件个数(fs.inotify.max_user_watches)与最大文件打开数量(DefaultLimitNOFILE)

均设置成:65535

保存设置后,重启服务器。

调试

测试

在仅做了站库分离配置nginx与PHP,嫂子在对我的搜索接口进行10K/s的post攻击后,我博客仅坚持了几秒,PHP就挂了。

在做好站库分离、(假)负载均衡、配置数据库、配置nginx与PHP、配置nginx防火墙后,嫂子通过GET,对我的时光机界面进行了30K/S的请求攻击,勉强能响应正常用户的访问,评论就算了。

设置了软硬文件句柄和打开文件的数目后我还没测试,不知道实际效果如何。

分析解决方法

通过分析错误日志,瓶颈还是在MySQL的服务器与网站后台服务器的通信带宽上,在嫂子测试过程中,直接跑满了500Mb内网带宽。PHP与nginx的报错倒没看到有多少。

Database-server-bandwidth.png

解决方法有两种,一种是加钱,阿里云的服务器配置越高内网带宽也越大。还有一种就是做(真)负载均衡,用多台数据库服务器共同分担压力。

其他

在测试过程中,腾讯云的云监控成功的给我发了短信提示,间接测试了我的云监控配置的还不错。

TODO

  1. 写个python脚本,处理nginx的日志,生成ip段来填入Nginx防火墙的黑名单中/用api填入腾讯云cdn。这也是为什么我要弄真实ip识别。
  2. 利用另一台服务器+安全狗一类软件做简易版WAF。
最后修改:2020 年 04 月 24 日
如果觉得我的文章对你有用,请随意赞赏