首页 > 系统相关 >Nginx 做静态文件服务器,多系统互相访问文件权限校验配置

Nginx 做静态文件服务器,多系统互相访问文件权限校验配置

时间:2024-05-10 19:11:07浏览次数:35  
标签:文件 Nginx request 校验 auth header token proxy nginx

问题背景:

接到个需求,客户有两个系统要互相访问文件,文件服务器是通过nginx搭建的,原来的访问地址如下:http://abc.cn/file/fa1a8d99a47b4c8c9d59152728af9930.docx

客户说这个不安全,任何人都能访问,一定要做权限校验

接到这个需求我觉得安全隐患不是很大,因为文件名是随机的,nginx也不支持在线预览目录,盲猜是很难猜出正确地址的,除非被抓包,这种概率很小

没办法,客户坚持说有问题,只能安排加上token验证了

这个还是多系统的互相访问,涉及到互相认证,有点复杂,经过一番研究解决了,特地记录下

 

解决方法:

首先贴出解决方法,nginx配置文件如下:

docker-compose

services:
      nginx-9002:
        image: nginx:latest
        restart: always
        hostname: nginx-9002
        container_name: nginx-9002
        #privileged: true
        environment:
          - "TZ=Asia/Shanghai"
        ports:
          - 9002:80
        volumes:
          - ./conf/nginx.conf:/etc/nginx/nginx.conf
          - ./conf/conf.d:/etc/nginx/conf.d/
          - ./logs/:/var/log/nginx/
          - ./ssl_key/:/data/ssl_key/
          - ./www/:/usr/share/nginx/html/

这个配置涉及http和server模块,所以把nginx.conf和conf.d分别映射出来了

nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/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" "$host"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  65;

    gzip  on;

    include /etc/nginx/conf.d/*.conf;


    client_max_body_size 300M;

    #安全加固
    keepalive_timeout 55;
    client_body_timeout 10;
    client_header_timeout 10;
    send_timeout 10;
    limit_conn ops 20;
    limit_conn_zone $binary_remote_addr zone=ops:10m;
    autoindex off;
    dav_methods off;
    server_tokens off;
    client_body_buffer_size 1K;
    client_header_buffer_size 1k;
    large_client_header_buffers 2 1k;

    add_header Content-Security-Policy  "default-src 'self' http://abc.cn/ http://1.1.1.1:9002 'unsafe-inline' 'unsafe-eval' blob: data:;";
    #add_header Content-Security-Policy "default-src 'self' 'unsafe-inline'";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; add_header X-Permitted-Cross-Domain-Policies "master-only"; add_header 'Referrer-Policy' 'origin'; add_header X-Download-Options "noopen" always; add_header Clear-Site-Data "storage"; add_header Cross-Origin-Embedder-Policy require-corp; add_header Cross-Origin-Opener-Policy same-site; add_header Cross-Origin-Resource-Policy same-site; add_header Permissions-Policy "interest-cohort=()"; #防止XSS攻击 add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; #判断文件访问链接参数,进行校验接口分发 map $request_uri $auth_url { #存在'&source=yg'参数的链接走对应系统的校验地址 ~*&source=yg http://1.1.1.1:9001/file/link/validate; #把自有系统接口地址设置为默认出参 default http://192.168.100.93:8085/file/link/validate; } }

default.conf

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

        #安全加固
        #防止盗链或者恶意域名解析
        if ( $host !~* 'abc.cn' )
        {
          return 403;
        }


        #限制请求类型
        if ($request_method !~ ^(GET|HEAD|POST)$ )
        {
          return 501;
        }


        #封杀各种user-agent
        if ($http_user_agent ~* "python|perl|ruby|curl|bash|echo|uname|base64|decode|md5sum|select|concat|httprequest|nmap|scan|nessus|wvs" ) {
          return 403;
        }

        #if ($http_user_agent ~* "" ) {
        #  return 403;
        #}

        #封杀特定的文件扩展名比如.bak以及目录;
        location ~* \.(bak|swp|save|sh|sql|mdb|svn|git|old)$ {
          rewrite ^/(.*)$  $host  permanent;
        }
        location /(admin|phpadmin|status)    { deny all; }
        stub_status off;





    location / {
        proxy_buffer_size 64k;
        proxy_buffers 32 32k;
        proxy_busy_buffers_size 128k;
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    #正式环境api接口
    location ^~/online-api/ {
        proxy_buffer_size 64k;
        proxy_buffers 32 32k;
        proxy_busy_buffers_size 128k;
        proxy_pass http://192.168.100.93:8085/;
    }

    #正式环境文件接口
    location ^~/online-file-api/ {
        proxy_buffer_size 64k;
        proxy_buffers 32 32k;
        proxy_busy_buffers_size 128k;
        proxy_pass http://192.168.100.93:9000/;
        #优化安全策略,使自有页面可以加载图片
        add_header X-Frame-Options "ALLOW-FROM http://aq.njjt.com.cn/";

        #把链接参数赋值到nginx内部参数
        set $token  $arg_token;
        set $from   $arg_from;

        #参数调试
        #add_header token $token;
        #add_header auth_url $auth_url;
        #add_header from $from;
        #add_header source $arg_source;
        #proxy_set_header X-Original-URI $request_uri;

        #跳转token校验
        auth_request /auth;

        #校验接口返回401直接跳转未认证链接处理
        error_page 401 = /unauthorized;
    }
    #token校验接口
    location = /auth {
#只能内部调用 internal; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; #设置token和from值到head proxy_set_header token $token; proxy_set_header from $from; #指定nginx域名解析dns #resolver 218.2.135.1 61.147.37.1; #把map的出参传入代理地址 proxy_pass $auth_url; } location = /unauthorized { #未认证用户直接返回403 return 403 'Access denied'; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } #安全素描 location /sketch { proxy_pass http://192.168.100.93:7777; } }

 

配置详解:

 

1.auth_request

由于我们项目已经开发完毕,这个只是安全改造,所以最佳的方式就是结合nginx来进行权限校验,找了一圈还真找到了

https://blog.csdn.net/u014374743/article/details/135937481

https://blog.csdn.net/nalanxiaoxiao2011/article/details/133769412

先来说思路,为nginx增加ngx_http_auth_request_module模块,实现基于子请求的结果的客户端的授权。如果子请求返回2xx响应码,则允许访问。如果它返回401或403,则访问被拒绝并显示相应的错误代码。子请求返回的任何其他响应代码都被认为是错误的。即在原来的基础上加了一层后端鉴权服务。

auth_request 这个就是这个配置的核心,当有请求来匹配到静态资源,会优先通过auth_request跳转到校验接口进行token校验,当校验成功则返回200状态,校验失败则返回401状态,auth_request收到200会返回相应的资源,收到401会抛出401报错

同时还发现另一种思路:https://www.cnblogs.com/lowmanisbusy/p/11718345.html

就是通过internal; 参数让静态文件只能接收内部访问,然后通过接口做校验,校验通过走内部访问,校验失败拒绝访问,这种是从接口层面直接进行token校验

但是考虑到多系统互相访问,要进行多系统分流校验,这种方式并不合适

于是就确定了用auth_request的方案,本以为问题就此愉快解决的时候,没想到,坑才刚刚开始。。

 

2.auth_request 根据参数分别请求不同验证地址

本来想法很简单

请求地址变为:http://abc.cn/file/fa1a8d99a47b4c8c9d59152728af9930.docx?token=xxxx&from=web&source=abc

后端把文件地址自动拼上token和其他参数传给前端,前端页面来访问

from=web/app 来区分客户端

source=abc/def 来区分系统

nginx自带参数arg_source来获取链接里的参数

在使用if语句判断,然后设置接口校验地址,最后把地址传给auth_request 不就行了,类似于这样

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        
            # 从查询参数中获取 token,并赋值给token变量
            set $token $arg_token;
            set $source $arg_source;
            # 自定义验证失败时的处理页面
            error_page 401 = /auth-required;
            if ($source ~ "jt") {
        set $flag $source;
                set $auth_path autha;
        }
            if ($source ~ "yg") {
        set $flag $source;
                set $auth_path authb;
        }
            add_header token $token;
            add_header from $arg_from;
            add_header flag $flag;
            add_header auth_path $auth_path;
            #auth_request /$auth_path;
            auth_request /authFileValidA;

    }

 

本来想的很完美,但是实际做起来 auth_request 并不能识别传参,打开http://abc.cn/file/fa1a8d99a47b4c8c9d59152728af9930.docx 照样能访问,nginx日志报错, invalid URL prefix in "auth-required"    auth_request 参数为空

把 auth_request 写成实际参数的时候,可以拒绝访问,试了很多次都是这样,无奈只好换种方式,于是我想到了给校验接口传参

类似于这样

        location = /authFileValidA {
            internal; # 只允许内部访问
            proxy_pass $auth_path;
            proxy_pass_request_body off;
            proxy_set_header Content-Length "";
            proxy_set_header X-Original-URI $request_uri;
            # 设置AccessToken 的值为token
            proxy_set_header token "$token";
            proxy_set_header from  "$arg_from";
        }

想法没毛病对吧,但是实际测试访问http://abc.cn/file/fa1a8d99a47b4c8c9d59152728af9930.docx 报500报错,token正确也报500,查看nginx日志报错 invalid URL prefix in ""    auth request unexpected status: 500,也是识别不到nginx

百度了一下,不得不说百度AI这次帮了不少忙,问了一下百度AI 

proxy_pass 支持传参吗

proxy_pass本身并不直接支持传参。proxy_pass主要用于将请求转发到另一个服务器,但它本身并不处理或传递参数。在Nginx配置中,proxy_pass指令用于定义代理服务器的地址,它将客户端的请求转发到该地址。

如果你需要在代理过程中传递参数,你可能需要使用其他方法或工具来实现。一种常见的方法是在Nginx配置中使用变量来构建代理URL,并在该URL中包含所需的参数。这样,每次请求时,Nginx都会根据这些变量动态地生成代理URL,并将请求转发到相应的地址。

需要注意的是,具体的实现方式可能因你的具体需求和Nginx版本而有所不同。因此,在实际应用中,你可能需要查阅Nginx的官方文档或相关资源,以了解如何根据你的需求进行配置和传参。

另外,如果你正在使用某种特定的编程语言或框架来处理代理请求,那么可能会有其他方式来实现传参的功能。在这种情况下,你可以查阅该语言或框架的文档以获取更多信息。

 

好吧,只能另辟蹊径了,于是我又问AI:

auth_request 根据参数分别请求不同验证地址
在Nginx配置中,auth_request指令允许你根据请求的参数来决定向不同的验证地址发送请求。以下是一个配置示例,其中使用了$arg_param变量来决定请求的验证地址:
http {
    map $arg_param $auth_url {
        default /auth;
        value1 /auth1;
        value2 /auth2;
    }
 
    server {
        location / {
            auth_request /auth;
            error_page 401 = /unauthorized;
        }
 
        location = /auth {
            internal;
            proxy_pass_request_body off;
            proxy_set_header Content-Length "";
            proxy_pass http://backend$auth_url;
        }
 
        location = /unauthorized {
            return 401 'Access denied';
        }
    }
}
在这个配置中:
map块定义了一个映射,根据请求参数param的值决定使用哪个验证URL。
当请求到达服务器块的location时,会自动触发auth_request指令,并将请求转发到/auth内部location。
proxy_pass使用了变量$auth_url,这是基于请求参数param的值动态决定的。
如果认证失败,会返回401错误。

说的很清楚,有木有,这就是我想要的map!

本以为问题就此迎刃而解的时候,一个坑又接踵而至。。

 

3.map条件判断

 

标签:文件,Nginx,request,校验,auth,header,token,proxy,nginx
From: https://www.cnblogs.com/allay/p/18185137

相关文章

  • Django 静态文件管理与部署指南
    title:Django静态文件管理与部署指南date:2024/5/1017:38:36updated:2024/5/1017:38:36categories:后端开发tags:WebOptCDN加速DjangoCompressWebpackStaticDeployCICD-ToolsSecStatic第一章:介绍Django静态文件的概念和重要性在Web开发中,静态文件......
  • 重命名文件(%使用)
    这个脚本会遍历当前目录下所有以.txt结尾的文件,并将它们的后缀名修改为.md。forfilein*.txt;domv--"$file""${file%.txt}.md"done${file%.txt}是Shell中的参数替换语法,它表示从变量$file的末尾匹配删除.txt字符串。这样,${file%.txt}就是将变量$file......
  • mybatis核心配置文件
    在resource目录下,创建mybatis-config.xml(官方建议起名方式)核心配置文件常用元素properties:通过resource属性从外部指定属性文件(db.properties),该属性文件描述数据库连接的相关配置(数据库驱动、连接数据库的url、数据库用户名、数据库密码),位置也是在/resources目录下settin......
  • Nginx请求访问控制是怎样实现的
    首先来看下什么是漏桶算法和令牌桶算法Nginx并不直接实现漏桶算法或令牌桶算法,但这些算法在控制网络流量和请求速率方面非常有用。这些算法通常在网络编程、API服务、负载均衡等领域中使用,以确保系统的稳定性和性能。漏桶算法(LeakyBucket):*漏桶算法用于限制数据的传输速率。它......
  • clickhuose config.xml文件
    <?xmlversion="1.0"?><yandex><logger><level>trace</level><log>/var/log/clickhouse-server/clickhouse-server.log</log><!--日志存放目录--><errorlog>/var/log/clic......
  • vite react 使用 svg 文件当作图标
    svg可以当做图标导入react里面,如果用img标签弄的话,无法控制图标颜色和字体大小,但是把他当组件导入的话,就可以这么控制了,比较方便,并且也方便webstorm预览首先安装vite-plugin-svgrpnpmaddvite-plugin-svgr-D然后使用修改vite.config.jsimport{defineConfi......
  • 在线htaccess换nginx工具
    htaccess换nginx工具为您提供htaccess与nginx在线转换,apache伪静态文件转为nginx重写规则,htaccess伪静态规则换nginx,apacheRewriteRule转rewrite,apache伪静态文件转nginx重写,apache转nginx重写规则,本工具支持所有的htaccess伪静态、基本的配置规则、重定向等转换为nginx。......
  • SpringBoot读取Resources下的文件
    packagecom.qzsl.dp.utils;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.core.io.Resource;importorg.springframework.core.io.ResourceLoader;importorg.springframework.stereotype.Component;importorg.springfr......
  • Linux nginx 玩转日志模块
    log_formatmain'$remote_addr-$remote_user[$time_local]"$request"''$status$body_bytes_sent"$http_referer"''"$http_user_agent""$http_x_forwarded_fo......
  • 网页根据屏幕宽度请求不同的CSS文件
    网页根据屏幕宽度请求不同的CSS文件前言:重在记录,可能出错。一、代码<!DOCTYPEhtml><htmllang="ch"> <head> <title>网页根据屏幕宽度请求不同的CSS文件</title> <linkid="desktop-style"media="onlyscreenand(min-width:960px)"type=&......