我们有一个 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 块。如果您想了解更多信息,这里有文档和文章:
- https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
- https://agentzh.blogspot.com/2011/03/how-nginx-location-if-works.html
更新:您可以做类似的事情。我自己还没有测试过,所以我认为它会有语法错误。但是,我想您明白了。
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 /{
...
}
...
}