V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
trzzzz
V2EX  ›  NGINX

请教一个 nginx 转发请求后, uri 的%28%29 被还原成()的问题

  •  
  •   trzzzz · 2023-11-14 17:04:25 +08:00 · 1799 次点击
    这是一个创建于 409 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景:系统 A 会将 uri 放入签名方法中生成签名,有一个 uri 中的参数是包含()左右括号(生成签名的时候左右括号是%28%29 ),系统 A 调用 nginx 代理的系统 B 的服务,请求到达系统 B 后 uri 变成了左右括号导致签名不正确

    我尝试直连系统 B ,签名能通过,但是走 nginx 签名就会出现上述的情况。下面是我的 nginx 配置

    http {
        include       mime.types;
        default_type  application/octet-stream;
    
        sendfile        on;
    
        keepalive_timeout  65;
    
    
        server {
            listen       80;
            server_name  localhost;
    
            location / {
                root   html;
                index  index.html index.htm;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
    
    
        upstream B {
            server 127.0.0.1:5300;
        }
    
        server {
            listen       15300;
    
            location / {
                client_max_body_size  2048M;
                client_body_buffer_size 128K;
                proxy_connect_timeout 180s;
                proxy_read_timeout 180s;
                proxy_send_timeout 180s;
                proxy_pass http://B/;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Original-URI $request_uri;
            }
        }
    }
    
    

    nginx.version=1.25.3

    请教各位大佬我应该如何解决这个问题

    18 条回复    2023-11-15 11:38:13 +08:00
    F7TsdQL45E0jmoiG
        1
    F7TsdQL45E0jmoiG  
       2023-11-14 17:11:17 +08:00
    计算签名应该显式调用相同的编码方法
    trzzzz
        2
    trzzzz  
    OP
       2023-11-14 17:20:47 +08:00
    @morenacl 是的,签名方法都一样,但是不同的是 A 服务器签名的时候 uri 中括号是%28%29 ,但经过 nginx 代理后到达服务器 B 的 uri 中就变成了()
    NessajCN
        3
    NessajCN  
       2023-11-14 17:35:29 +08:00
    你说的究竟是生成完的签名进 B 验证还是 B 就是签名生成服务?
    trzzzz
        4
    trzzzz  
    OP
       2023-11-14 17:43:53 +08:00
    @NessajCN A 生成签名到 B 后,B 是拿 request 里面的内容进行签名后对比 A 传来的签名。签名没办法被解析出来
    ysc3839
        5
    ysc3839  
       2023-11-14 17:44:54 +08:00 via Android
    去掉 X-Original-URI 呢?
    julyclyde
        6
    julyclyde  
       2023-11-14 17:52:59 +08:00
    proxy_pass 那个 B 后面为什么还带了“根目录”斜线呢?
    trzzzz
        7
    trzzzz  
    OP
       2023-11-14 18:05:48 +08:00
    @ysc3839 这个是后来加上的,去掉也试过
    trzzzz
        8
    trzzzz  
    OP
       2023-11-14 18:06:42 +08:00
    @julyclyde 我试着去掉看看,一开始加上没报错就没管了
    yinmin
        9
    yinmin  
       2023-11-14 21:50:59 +08:00 via iPhone
    建议你参考 alipay 接口的签名方式,基于 decode 出来的 utf-8 编码进行签名
    trzzzz
        10
    trzzzz  
    OP
       2023-11-14 22:44:41 +08:00
    @yinmin 主要 A 服务器的签名方法是用的 sdk ,里面是把 uri 先 encode 后再签的,这样()就会变成%28%29 。其实直连 B 服务器是签名能过,但为了负载加了 nginx 后就有()签名不过的场景。想的是在 nginx 加什么配置能解决
    phithon
        11
    phithon  
       2023-11-15 00:43:03 +08:00   ❤️ 1
    A request URI is passed to the server as follows:

    If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:

    ```
    location /name/ {
    proxy_pass http://127.0.0.1/remote/;
    }
    ```

    If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:

    ```
    location /some/path/ {
    proxy_pass http://127.0.0.1;
    }
    ```

    加不加 trailing slash 会完全不一样。
    trzzzz
        12
    trzzzz  
    OP
       2023-11-15 09:08:36 +08:00
    @phithon Thanks!!!! :)
    F7TsdQL45E0jmoiG
        13
    F7TsdQL45E0jmoiG  
       2023-11-15 09:12:42 +08:00
    @trzzzz 你还陷在 Nginx 里,这个和 Nginx 没关系。
    trzzzz
        14
    trzzzz  
    OP
       2023-11-15 09:13:51 +08:00
    @morenacl 我按照 11 楼给出的建议,把 trailing slash 去掉后就正常了
    F7TsdQL45E0jmoiG
        15
    F7TsdQL45E0jmoiG  
       2023-11-15 09:15:02 +08:00
    @trzzzz A:参数字符串->urlencode->计算签名,发送到 B ,B 要做同样的操作参数字符串->urlencode->计算签名,不管是用 urlencode 还是 base64 等,先要保持编码一致,编码一致。
    trzzzz
        16
    trzzzz  
    OP
       2023-11-15 09:17:25 +08:00
    @morenacl 是的,计算签名的时候需要保证这点。但 A 和 B 都是从 request 中取出 uri 进行计算的,经过 nginx 转发后,B 拿出的 uri 中的括号就不是%28%29 了。但直连是正常的,所以怀疑 nginx 哪里配置没对
    F7TsdQL45E0jmoiG
        17
    F7TsdQL45E0jmoiG  
       2023-11-15 09:21:55 +08:00
    @trzzzz B 要做 urlencode
    julyclyde
        18
    julyclyde  
       2023-11-15 11:38:13 +08:00
    @trzzzz 显然是连 URI 都不对。更别提 querystring 了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1223 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 47ms · UTC 18:01 · PVG 02:01 · LAX 10:01 · JFK 13:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.