在查看网站日志时,会发下有许多的恶意扫描和垃圾爬虫,为了网站安全和减轻服务器压力,我们应该想办法阻止这些垃圾请求。
具体操作就是,先通过 Nginx 访问日志,查看哪些是垃圾请求,然后通过 Nginx 配置,屏蔽他们访问。
本人网站的 Nginx Access 日志在:/var/log/nginx/ 目录。
$ nginx -v
nginx version: nginx/1.18.0
屏蔽恶意IP地址
(1)使用 awk 命令查询访问最频繁的IP:
$ awk '{print $1}' access.log|sort | uniq -c |sort -n -k 1 -r|more
说明,使用 awk 命令拆分日志,打印第一列($1表示第一列,默认的 access日志,第一列是IP地址),排序和去重后查看。
(2)使用 deny 指令屏蔽 IP
获取到恶意访问的IP后,我们可以使用 deny 指令来屏蔽。
可以指定单个IP,也可以按照IP段进行屏蔽。以下是屏蔽示例:
http {
deny 108.179.194.35; # 扫描 wordpress
deny 159.203.31.171; # 扫描 wp-login
deny 158.69.243.0/24; # MJ12bot
deny 46.229.168.0/24; # SemRush
deny 54.36.148.0/24; # AhrefsBot
deny 54.36.149.0/24; # AhrefsBot
}
备注: deny 指令可以在 Nginx 的 http, server, location 上下文中指定。
(3)另外还有一个 allow 指令,指明哪些请求可以访问。
对于仅限特定用户访问的内容,我们可以指明其允许访问的IP。比如网站管理后台的链接,仅限指定的ip段访问。
location /admin {
allow 192.168.1.0/24;
allow 112.66.77.88;
allow 112.65.12.0/24;
deny all;
}
说明,这里配置的,除了指定的几个ip 或 ip段,剩下的全部拒绝访问。
根据客户端的请求链接屏蔽访问
(1)使用 awk 命令查询访问最频繁的链接
$ awk '{print $7}' access.log|sort | uniq -c |sort -n -k 1 -r|more
说明,本人网站的 access.log 第7列为 url 地址(Nginx默认配置),如果指明了nginx日志格式,可能会有不同。
(2)找出这些恶意的访问地址
这里列出一些访问比较多的恶意链接
/wp-signin.php?dizo&ping
/wp-login.php
/wp-includes/css/wp-config.php
/wp-includes/wlwmanifest.xml
/.env
/phpMyAdmin-2.6.3/
/phpMyAdmin-2.6.2/
/root.rar
/bak.zip
/wang123.net1.rar
/wang123.net1.zip
/wang123.net2.rar
/wang123.net2.zip
/inc/config.asp
/config/AspCms_Config.asp
/.aws/.credentials.swp
/.aws/config
可以看到这是在扫描 WordPress 和 phpMyAdmin、下载网站的压缩包、扫描网站可能存在的配置。
在 Nginx 中,我们可以使用 $document_uri 来获取到请求 uri,根据 uri 我们来判断哪些后缀的请求我们拒绝其访问。
(3)现根据后缀名屏蔽掉一批请求:
# 屏蔽恶意访问
if ($document_uri ~* \.(php|asp|aspx|jsp|swp|git|env|yaml|yml|sql|db|bak|ini|docx|doc|rar|tar|gz|zip|log)$) {
return 404;
}
说明,这里使用 if 语句,匹配以 .
开始,以 php、asp 、jsp 、env 等后缀结尾的文件,如果存在,nginx 则直接返回 404 给客户端。
注意,这里的配置的后缀仅供参考,按需配置,比如你如果想让用户下载doc文件,就把 doc|docx 去掉。
Tips: 变量 $document_uri ($uri) 与 $request_uri 有什么不同?
比如访问链接是 https://wang123.net/posts/test.db?wd=test&limit=5
$document_uri 变量的值为:/posts/test.db
$request_uri 变量的值为: /posts/test.db?wd=test&limit=5
(3)在根据关键词屏蔽一批请求:
对于一些我们不能按照后缀进行屏蔽的链接,比如 /wp-includes/wlwmanifest.xml ,这个 xml 后缀不能屏蔽(因为网站其他地方有要用的xml链接,因此我们改用其他关键词进行屏蔽。
根据请求 uri 里的的关键词进行屏蔽,示例如下:
if ($document_uri ~* (wordpress|phpinfo|wlwmanifest|phpMyAdmin|xmlrpc)) {
return 404;
}
说明,这里匹配几个特定关键词,匹配上来直接返回 404 错误。再访问 /wp-includes/wlwmanifest.xml 会直接 404。
注意,这里的配置要谨慎,如果配置了,url链接里就不能有这些关键词了,否则 nginx 则直接返回 404 错误。
屏蔽恶意爬虫
浏览器或者爬虫工具访问,一般都会带有 User Agent (浏览器用户标识)。
我们根据一些关键词,屏蔽特定的爬虫或工具。
在 Ngxin 中,$http_user_agent 变量可以获取到 用户的 UA ,匹配到我们指定的关键词,直接返回 403 无权访问。
server {
# 禁止Scrapy等工具的抓取
if ($http_user_agent ~* (Scrapy|HttpClient|PostmanRuntime|ApacheBench|Java||python-requests|Python-urllib|node-fetch)) {
return 403;
}
# 禁止指定的 user agent 以及为空的访问
if ($http_user_agent ~ "Nimbostratus|MJ12bot|MegaIndex|YisouSpider|^$" ) {
return 403;
}
}
注意,这里仅列出来了部分爬虫的 UA 关键词,更多的可以去网上搜索“垃圾爬虫”。
有些爬虫也支持 robots 协议, 因为我们在网站根目录的 robots.txt 中也可以都加上。
User-agent:*
Disallow:/dashboard
Disallow:/admin
Disallow:/static
Disallow:/assets
User-Agent: AhrefsBot
Disallow: /
User-Agent: MJ12bot
Disallow: /
User-Agent: DotBot
Disallow: /
User-Agent: SemrushBot
Disallow: /
User-Agent: MauiBot
Disallow: /
对IP和服务进行限流
Nginx 提供了2个模块来处理限流,分别是 ngx_http_limit_conn_module 和 ngx_http_limit_req_module 模块
这里我们使用 ngx_http_limit_conn_module 里的 limit_conn_zone 和 limit_conn 指令配置,限制请求的连接数。
http {
##### limit
limit_conn_zone $binary_remote_addr zone=perIP:10m;
limit_conn_zone $server_name zone=perServer:10m;
limit_conn perIP 10;
limit_conn perServer 200;
limit_conn_status 503;
}
limit_conn_zone 配置存在的连接的空间(zone),一个名字叫 perIP,一个名字叫 perServer,空间的大小都指定大小为 10m 。
limit_conn perip 10 作用的 key 是 $binary_remote_addr,表示限制单个IP同时最多能持有10个连接。
limit_conn perserver 200 作用的 key 是 $server_name,表示虚拟主机(server) 同时能处理并发连接的总数为 200。
limit_conn_status 表示,如果超出链接,直接返回 503 错误。
注意, limit_conn 的数值按需调整。上边的配置会对全站都生效。如果只是想对某个 uri 限流,可以将 limit_conn 写在 location 上下文里。
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
location /download/ {
limit_conn addr 1;
}
}
}
总结
为了方便管理,我们创建两个配置文件,对ip和spider分别管理。
屏蔽IP访问 block_ips.conf
deny 108.179.194.35; # 扫描 wordpress
deny 159.203.31.171; # 扫描 wp-login
deny 158.69.243.0/24; # MJ12bot
deny 46.229.168.0/24; # SemRush
deny 54.36.148.0/24; # AhrefsBot
deny 54.36.149.0/24; # AhrefsBot
屏蔽UA访问 block_spiders.conf
# 禁止Scrapy等工具的抓取
if ($http_user_agent ~* (Scrapy|HttpClient|PostmanRuntime|ApacheBench|Java||python-requests|Python-urllib|node-fetch)) {
return 403;
}
# 禁止指定的 user agent 以及为空的访问
if ($http_user_agent ~ "Nimbostratus|MJ12bot|MegaIndex|YisouSpider|^$" ) {
return 403;
}
# 屏蔽恶意访问
if ($document_uri ~* \.(php|asp|aspx|jsp|swp|git|env|yaml|yml|sql|db|bak|ini|docx|doc|rar|tar|gz|zip|log)$) {
return 404;
}
# 屏蔽指定关键词
if ($document_uri ~* (wordpress|phpinfo|wlwmanifest|phpMyAdmin|xmlrpc)) {
return 404;
}
这样在 nginx.conf 中就可以直接 include 进来了。
http {
include mime.types;
default_type text/html;
##### limit 限流
limit_conn_zone $binary_remote_addr zone=perIP:10m;
limit_conn_zone $server_name zone=perServer:10m;
limit_conn perIP 10;
limit_conn perServer 200;
limit_conn_status 503;
### 引入屏蔽规则
include /etc/nginx/block_ips.conf;
include /etc/nginx/block_spiders.conf;
### 其他配置
}
重启 nginx 即可生效。 (本机的nginx,是使用 apt 包安装的,可以直接 使用 systemctl 管理 nginx 服务)。
$ systemctl reload ngxin # 重新加载
$ systemctl restart ngxin # 重启
$ systemctl status ngxin # 查看状态
$ systemctl start ngxin # 启动
$ systemctl stop ngxin # 停止
温馨提示,重启前记得测试 配置文件是否有错误。
$ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
确保测试通过后再重启哦。
参考链接
https://ssrvps.org/archives/5370