NGINX 反向代理,具有可选的 SSL 客户端身份验证

NGINX 反向代理,具有可选的 SSL 客户端身份验证

我们有一个 NGINX 代理,它应该在https://服务器/应用程序/以及位于https://服务器/. 额外的困难是通过 SSL 客户端身份验证来保护 API。

这是我对 NGINX 服务器配置的尝试:

server {
    listen       443 ssl;
    server_name  server;

    ssl_certificate     /etc/nginx/certs/site.crt;
    ssl_certificate_key /etc/nginx/certs/site.key;

    ssl_client_certificate /etc/nginx/certs/rootCA.pem;
    ssl_verify_client optional;

    location / {
        if ($request_method = GET) {
            return 301 https://$host/app/;
        }

        if ($ssl_client_verify != SUCCESS) {
            return 403;
        }

        limit_except GET {
            allow <SOME_IP>;
            deny  all;
        }

        add_header X-Client-Authentication "$ssl_client_verify";

        proxy_pass http://backend:8080/;
    }

    location /app {
        ...
    }
}

不幸的是,即使是未经身份验证的客户端也会被转发到后端。这怎么可能呢?该if($ssl_client_verify != SUCCESS)行应该处理这种情况。我将的内容添加$ssl_client_verify到回复标头中,结果与NONE预期一致。因此,显然,if带有的语句return 403未被评估。

顺便说一句,我无法将 API 移动到其他端口或路径

答案1

在 location 块中使用 if 指令是需要避免的。因为 nginx 配置使用声明性语言。因此,如果您在 location 块中使用 if 指令,并且第一个 if 指令条件满足,则不会执行另一个 if 指令。所以我的建议是将 if 指令从 location 块更改为 server 块。如果您想了解更多信息,这里有文档和文章:

更新:您可以做类似的事情。我自己还没有测试过,所以我认为它会有语法错误。但是,我想您明白了。

server{
    ...

    #for location /
    set $Location_VerifySSL 'root';

    #for location /app/
    if ($request_uri ~* '^(/app)){
        set $Location_VerifySSL 'app';
    }

    set $Location_VerifySSL "$Location_VerifySSL_success";
    if ($ssl_client_verify != 'SUCCESS'){
        set $Location_VerifySSL "$Location_VerifySSL_fail";
    }

    if ($Location_VerifySSL = "root_fail") {
        return 403;
    }
    if ($Location_VerifySSL = "app_success") {
        return 200 'This is when url match ^(/app) and ';
    }
    ...

    location /{
        ...
    }
    ...
}

相关内容