通过nginx拦截带时间戳的恶意访问

日志中出现 /?_=1676277219011 的请求,后面13位数是时间戳,大量的请求导致后端php资源池耗尽从而报502错误。
现通过nginx拦截这些恶意请求。

开始用location拦截,过滤参数,发现这样是错误的。

原因是 location 不能拦截参数,因为location是根据uri处理的,uri不包含参数部分。

先看下 $request_uri 和 $args 两个内置变量的值

location /
{
    return 200 $request_uri;
}

访问结果:/test.html?id=1&time=1676277219011

location /
{
    return 200 $args;
}

访问结果:id=1&time=1676277219050

2种拦截思路:

# 这个是拦截请求参数中以13位数字结尾的

if ($args ~ "[0-9]{13}$")
{
   return 403;
}

# 这个是拦截请求路径为 /?_=带13位数字结尾的

if ($request_uri ~* "^/\?_=[0-9]{13}$")
{
    return 403;
}

nginx自定义error_page 403页面与deny ip冲突

nginx中可以通过error_page指令自定义403状态码(包括其他错误状态码)错误页面
当与deny ip共存时,则仍会返回nginx内置的403提示页面,自定义的页面并没有生效。
403.html在网站根目录下。
nginx配置:

allow 116.179.37.0/24;
allow 116.179.32.0/24;
allow 111.206.198.0/24;
deny all;

error_page 403 /403.html;

这样配置的话,自定义页面无效。

原因:
deny指令把所有的访问给deny了,所以需要用location拦截这个页面,允许所有访问。

有效配置:

allow 116.179.37.0/24;
allow 116.179.32.0/24;
allow 111.206.198.0/24;
deny all;

error_page 403 /403.html;
location /403.html
{
	allow all;
}

nginx绑定大量域名时需要修改的两个参数

nginx在添加量大虚拟主机时重启nginx报错。

nginx: [warn] could not build optimal server_names_hash, you should increase either server_names_hash_max_size: 512 or server_names_hash_bucket_size: 64; ignoring server_names_hash_bucket_size
http {
    include       mime.types;
    default_type  application/octet-stream;

    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  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    # 添加或修改下面2行
    server_names_hash_max_size 4096;
    server_names_hash_bucket_size 1024;

    include vhost/*.conf;
}

nginx虚拟主机监控nginx-module-vts模块

可以查看每个虚拟主机的请求情况,发送流量,upstream分流等情况,且支持prometheus监控。
编译模块略…
# nginx.conf配置文件

http
{
	略```
	
	# 开启监控
	vhost_traffic_status_zone;
	
	# 根据主机名区分
	vhost_traffic_status_filter_by_host on;

	include /usr/local/nginx/conf/vhost/vhost_*.conf;
}

# 修改其中一个虚拟主机,添加访问监控用于展示。

server
{
    listen 80 default_server;
    server_name www.test.com;
	略```
	location /status
	{
		vhost_traffic_status_display;
		vhost_traffic_status_display_format html;
	}
	略```
}

展示页面里的虚拟主机看着是不全,其实是需要访问以后才会产生统计数据,否则是不显示的。
如果某个虚拟主机不想参与统计,则在server{}段中加入 vhost_traffic_status off;
更多指令参考:https://github.com/vozlt/nginx-module-vts

nginx反向代理proxy_pass中带/和不带/的区别

文档:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

环境:
192.168.31.36 nginx反向代理
192.168.31.37 nginx,默认首页为index.html

通过浏览器访问:http://www.test.com/test/index.html 测试

情况一、
proxy_pass中不包含URI地址,那么location后的地址会传递给后端。
1、

location /test
{
	proxy_pass http://192.168.31.37;
}

因为后端没有test目录,所以访问结果为 404(后端日志 “GET /test/index.html HTTP/1.0” 404)

2、

location /test/   # location中以/结尾
{
	proxy_pass http://192.168.31.37;
}

因为后端没有test目录,所以访问结果为 404(后端日志 “GET /test/index.html HTTP/1.0” 404)

情况二、
proxy_pass中指定了符合URI规范的地址,那么location后面匹配的地址字符被替换为proxy_pass中URI的地址字符
3、

location /test
{
    proxy_pass http://192.168.31.37/;
}

proxy_pass中的/替换为/test,实际访问 http://192.168.31.37//index.html,所以访问成功(后端日志 “GET //index.html HTTP/1.0” 200)
实际访问地址里出现//的原因是访问
/test/index.html 时,proxy_pass后面的/替换为/test,变成
//index.html
所以日志里也会看到两个//。

4、

location /test/
{
	proxy_pass http://192.168.31.37/;
}

访问成功(后端日志 “GET /index.html HTTP/1.0” 200)
/ 替换 /test/ 后就变为 /index.html ,所以日志里只出现一个 /