【问题标题】:Nginx conditional client certificate authenticationNginx 条件客户端证书认证
【发布时间】:2018-06-09 05:57:28
【问题描述】:

我正在尝试使用 Nginx 代理流量。我在 HTTPS 上侦听的配置中有一个服务器块,它既提供有效证书又检查客户端证书(2 路 ssl)。此设置有效,但我希望能够让我们的开发人员在客户端证书验证的情况下访问服务器(因为他们显然不会拥有它)。我之前使用的配置是:

server {
    listen       443 ssl http2 default_server;
    server_name  api.website.com;
    root         /usr/share/nginx/html;
    underscores_in_headers on;

    ssl_certificate "/etc/pki/nginx/private/ServerCert.pem";
    ssl_certificate_key "/etc/pki/nginx/private/ServerCert.pem";
    ssl_client_certificate "/etc/pki/nginx/ClientCert.pem";
    ssl_verify_client on;
    ssl_verify_depth 2;
    ssl_dhparam "/etc/pki/nginx/dhparams.pem";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  1m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
    ssl_prefer_server_ciphers on;
    include /etc/nginx/default.d/*.conf;

    location /tomcat/endpoint {
        proxy_pass http://localhost:8080/tomcat-war;
        proxy_pass_request_headers      on;
    }
}

同样,这有效,但有效地锁定了访问权限,除了我添加到客户端证书存储的证书。一种解决方案是制作一个内部签名的证书并将其添加到商店,然后分发给我们的开发人员,但我宁愿将开发人员排除在基于 IP 地址的此类检查之外。我设法通过将 ssl_client_verify 更改为可选并将位置块更改为以下内容来做到这一点:

location /tomcat/endpoint {
  set $allowed 9;
  if ($ssl_client_verify != "SUCCESS") { set $allowed 1;}
  if ($not_internal_ip) { set $allowed  "${allowed}1"; }
  if ($allowed = 11) {
      return 403;
  }
  proxy_pass http://localhost:8080/tomcat-war;
  proxy_pass_request_headers      on;
}

其中 $not_internal_ip 设置为地理块,如下所示:

geo $not_internal_ip {
  default 0;
  10.0.0.0/8 1;
  172.16.0.0/12 1;
  192.168.0.0/16 1;
}

尽管这可行,但我担心逻辑依赖于这么多 if 语句,它们是 Nginx 配置文件中的 notoriously dangerous

如果这种方式在location块中使用if语句安全吗?有没有更好的方法来做到这一点?

【问题讨论】:

    标签: ssl nginx configuration ip certificate


    【解决方案1】:

    你可以不用 if 语句也可以使用映射来做到这一点

    geo $internal_ip {
      default no;
      10.0.0.0/8 yes;
      172.16.0.0/12 yes;
      192.168.0.0/16 yes;
    }
    
    map $internal_ip$ssl_client_verify $request_allowed {
      ~* "^yes" yes;
      "noSUCCESS" yes;
      default no;
    }
    
    map $request_allowed $proxy_pass_url {
       yes  "http://localhost:8080/tomcat-war/$request_uri";
       no   "/access-denied";
    }
    
    location /tomcat/endpoint {
       proxy_pass $proxy_pass_url;
       proxy_pass_request_headers      on;
    }
    
    location /access-denied {
       return 403;
    }
    

    PS:我没有测试过上面的配置,但我过去使用过类似的方法

    【讨论】:

    • 我真的很喜欢它的发展方向,我知道它是如何工作的,但它如何适应多个位置呢?我在原始帖子中没有这么说,但我实际上是根据 URI 代理了一些不同的战争。我想我可以用重写规则替换位置,但我希望有单独的位置块。
    • 您可以在 $request_allowed 上使用一个 if 并使用它,否则您必须将 map $request_allowed $proxy_pass_url 更改为 map $request_allowed$request_uri $proxy_pass_url,然后在地图中使用模式以指向不同的战争 URL跨度>
    • 顺便说一句,我测试了这个并且它有效。唯一需要改变的是正则表达式(应该是 ~*^yes all-together)。我还选择了 location 块中的单个 if 语句。通过匹配否定条件并返回 403,它不应该中断。感谢您的帮助!
    猜你喜欢
    • 2019-07-04
    • 2017-06-08
    • 2015-09-06
    • 2010-11-30
    • 2012-09-04
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    相关资源
    最近更新 更多