【问题标题】:Nginx - Decode URL query parameter and forward it as request headerNginx - 解码 URL 查询参数并将其作为请求标头转发
【发布时间】:2019-01-14 11:17:40
【问题描述】:

我需要以查询参数(例如http://example.com?BASIC_AUTH=dXNlcjpwYXNz)的形式向 nginx 发送一些基本的身份验证凭据(例如 user:pass),并能够以更常见的 Authorization: Basic dXNlcjpwYXNz 标头形式将它们转发到代理后面的目标服务器。

我已经能够使用正则表达式检索编码的身份验证字符串的值。问题是该值通常可能包含一些需要在 URL 中进行百分比编码的字符。埃斯。 user:pass! -> ?BASIC_AUTH=dXNlcjpwYXNzIQ== 变为 ?BASIC_AUTH=dXNlcjpwYXNzIQ%3D%3D

因此,当我将请求转发到目标服务器时,我最终指定了目标服务器将拒绝的 Authorization: Basic dXNlcjpwYXNzIQ%3D%3D,并给出 401 Unauthorized。

如何在设置 Authorization 标头之前强制 nginx 解码 auth 字符串?提前感谢您的帮助。

注意:由于某些特定于应用程序的限制,我首先无法在 Authorization 标头中发送 auth 字符串。

【问题讨论】:

    标签: nginx basic-authentication urlencode url-encoding


    【解决方案1】:

    “纯”nginx解决方案

    遗憾的是 nginx 没有提供丰富的字符串操作集。我认为没有办法通过一些字符串进行全局搜索和替换(如果我们可以将所有%2B 替换为+%2F/%3D 替换为=)。但是,在某些情况下,nginx 会对某些字符串执行 urldecoding - 当此字符串成为将转发到上游代理服务器的 URI 的一部分时。

    因此我们可以将BASIC_AUTH 请求参数的值添加到 URI 并向我们自己发出代理请求:

    # Main server block
    server {
        listen 80 default_server;
        ...
    
        location / {
            if ($arg_basic_auth) {
                # "basic_auth" request argument is present,
                # append "/decode_basic_auth/<BASE64_token>" to the URI
                # and go to the next location block
                rewrite ^(.*)$ /decode_basic_auth/$arg_basic_auth$1 last;
            }
            # No "basic_auth" request argument present,
            # can do a proxy call from here without setting authorization headers
            ...
        }
    
        location /decode_basic_auth/ {
            # This will be an internal location only
            internal;
            # Remove "basic_auth" request argument from the list of arguments
            if ($args ~* (.*)(^|&)basic_auth=[^&]*(\2|$)&?(.*)) {
                set $args $1$3$4;
            }
            # Some hostname for processing proxy subrequests
            proxy_set_header Host internal.basic.auth.localhost;
            # Do a subrequest to ourselfs, preserving other request arguments
            proxy_pass http://127.0.0.1$uri$is_args$args;
        }
    }
    
    # Additional server block for proxy subrequests processing
    server {
        listen 80;
        server_name internal.basic.auth.localhost;
    
        # Got URI in form "/decode_basic_auth/<BASE64_token>/<Original_URI>"
        location ~ ^/decode_basic_auth/([^/]+)(/.*)$ {
            proxy_set_header Authorization "Basic $1";
            # Setup other HTTP headers here
            ...
            proxy_pass http://<upstream_server>$2$is_args$args;
        }
    
        # Do not serve other requests
        location / {
            return 444;
        }
    }
    

    也许这不是一个非常优雅的解决方案,但它已经过测试并且有效。

    OpenResty / ngx_http_lua_module

    这可以通过openrestyngx_http_lua_module 使用ngx.escape_uri 函数轻松解决:

    server {
        listen 80 default_server;
        ...
    
        location / {
            set $auth $arg_basic_auth;
            if ($args ~* (.*)(^|&)basic_auth=[^&]*(\2|$)&?(.*)) {
                set $args $1$3$4;
            }
            rewrite_by_lua_block {
                ngx.var.auth = ngx.unescape_uri(ngx.var.auth)
            }
            proxy_set_header Authorization "Basic $auth";
            # Setup other HTTP headers here
            ...
            proxy_pass http://<upstream_server>;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-04
      • 2016-11-14
      • 2022-06-29
      • 2019-01-09
      相关资源
      最近更新 更多