使用Nginx和Tomcat Web应用程序进行TLS客户端身份验证

3
我有一个 Tomcat 8 的 web 应用程序,它在服务器上的端口 8080 上运行。任何对端口 443 的传入请求都将使用 Nginx 转发到 localhost:8080,以提供 Web 应用程序服务。
我正在尝试设置双向身份验证,并解析应用程序用于身份验证的客户端证书。然后,应用程序将使用此信息来确定用户是否应具有“管理员”或“用户”权限。客户端证书将在公共名称(CN)字段中带有字符串“管理员”或“用户”。
我能够实现双向身份验证,以下是当前的 nginx ssl.conf。但问题是证书信息未传递给 Tomcat Web 应用程序来解析数据。在 Nginx 中是否有一种可用的方法来传递客户端证书数据,以便 Tomcat 8 应用程序可以使用它?
server {
    listen       443 default_server;
    server_name  name.domain.com;

    ssl on;
    ssl_certificate /etc/nginx/self-signed.pem;
    ssl_certificate_key /etc/nginx/self-signed.pem;
    ssl_protocols SSLv2 TLSv1 TLSv1.1 TLSv1.2;


    ssl_client_certificate /etc/nginx/ca.cert.pem;
    ssl_verify_client optional;
    ssl_verify_depth  2;
    ssl_session_timeout  5m;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers  on;


    port_in_redirect off;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    #test page for the load balancer
    location /loadbalancer {
      add_header X-Frame-Options "DENY";
      auth_basic off;
      #proxy_pass http://localhost:8080;
      try_files $uri /test.html;
    }

    location /webapi {
      add_header X-Frame-Options "DENY";
      auth_basic off;
      proxy_pass http://localhost:8080;
    }

    location / {
      if ($ssl_client_verify != SUCCESS)

     {
      return 403;
      break;
     }

      add_header X-Frame-Options "DENY";
      proxy_pass http://localhost:8080;
    }


    error_page  404              /404.html;
      location = /404.html {
      root   /usr/share/nginx/html;
    }

    error_page   500 502 503 504  /50x.html;
      location = /50x.html {
      root   /usr/share/nginx/html;
    }
}
1个回答

4
你可以使用proxy_set_header指令向你的Tomcat传递额外的标头。
可用变量

http://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_cipher

例子

proxy_set_header SSL_DN $ssl_client_s_dn;

在您的Java应用程序中,您可以读取这些标头以进行进一步处理。
顺便说一下,我不会将访问级别保存在证书中,而是保存在服务器端数据库中,这样您可以更轻松地重新分配/更改/添加角色或撤销有效证书。
编辑:实际上,nginx也支持证书吊销列表: http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_crl 对于nginx + php的好文章,可以轻松地适应您的用例。

http://nategood.com/client-side-certificate-authentication-in-ngi


1
这个 proxy_set_header SSL_DN $ssl_client_s_dn; 确实有效!谢谢。 - OK999
1
请注意,如果您想要完整的证书,有两个变量:ssl_client_cert,其中Nginx将用制表符替换\n;而ssl_client_raw_cert具有换行符但会中断您的HTTP连接。使用官方Tomcat SSL阀门无法工作(仅替换为空格而不是制表符)。 - lucasvc
1
官方的 Nginx文档中并没有提到“\n”会被替换,仅提到“\t”会被添加(但实际上“\n”会被替换)。链接如下:http://nginx.org/en/docs/http/ngx_http_ssl_module.html - Khanna111
这是一篇关于该主题(以及\n问题)的好文章: https://blog.perplexedminds.com/2015/04/nginx-apache-tomcat-certificate.html - Martynas Jusevičius
@OK999 - 在添加了proxy_set_header之后,它是否与在tomcat上存在客户端身份验证时完全相同?也就是说,您能否在X509AuthenticationFilter类中接收证书,如下所示: X509Certificate[] certs = (X509Certificate[])((X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate")) ? - veritas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接