客户端 tls解密_TLS客户端身份验证

本文探讨了在Java应用中实现TLS客户端身份验证的两种方法:直接配置Tomcat和通过Nginx负载均衡器。介绍了如何处理客户端证书,以及如何在Spring Security框架下进行身份验证,同时讨论了在不同场景下的优缺点和可用性问题。
摘要由CSDN通过智能技术生成

客户端 tls解密

我决定为电子识别方案设计一个原型,因此我研究了如何使用Java / Spring服务器端进行TLS客户端身份验证(即使您不是Java开发人员,也可以继续阅读-大部分文章是Java -不可知)。

为什么要进行TLS客户端身份验证? 因为这是认证拥有证书的用户(例如,在智能卡上)的最标准方法。 当然,智能卡证书并不是唯一的应用程序–组织可以向存储在其计算机上的用户颁发内部证书。 关键是要具有比简单的用户名/密码对更安全的身份验证机制。 这是一个可用性问题,尤其是对于智能卡,但这超出了本文的范围。

因此,使用TLS clientAuth,除了由客户端(通过服务器证书)验证服务器身份之外,客户端身份也由服务器验证。 这意味着客户端具有由服务器颁发的权威机构颁发的证书。 粗略地说,客户端必须对挑战进行数字签名,以证明其拥有与其所提供的证书相对应的私钥。 (此过程也可以在“相互认证”下找到)

有两种解决方法。 第一个也是最直观的方法是检查如何配置Tomcat(或servlet容器)。 Spring Security x509身份验证页面在底部提供了Tomcat配置。 “密钥库”是存储服务器证书(+私钥)的存储,“ trustStore”是保存用于签署客户端证书的授权机构的根证书的存储。

但是,仅当您向用户公开了单个servlet容器实例时,该配置才适用。 不过,在生产中最有可能的情况是,您将在负载平衡器后面有许多实例/节点在运行您的应用程序,并且TLS通常在负载平衡器处终止 ,然后将解密的请求通过一个容器转发到servlet容器。纯HTTP连接。 在这种情况下,您的选择是不终止负载均衡器的TLS(这很可能不是一个好主意),或者您必须以某种方式将客户端证书从负载均衡器转发到节点。

我将以nginx为例。 生成密钥对,证书,证书签名请求,签名的证书和密钥库值得一提。 我已经概述了这里需要的东西 。 您需要openssl和keytool / Portecle以及一堆命令。 当然,对于生产来说,它甚至更加复杂,因为对于服务器证书,您需要将CSR发送到CA。 完成此操作后,在您的nginx配置中,您应该具有以下内容:

server {
   listen 443 ssl;
   server_name yourdomain.com;

   ssl_certificate server.cer;
   # that's the private key
   ssl_certificate_key server.key;
   # that holds the certificate of the CA that signed the client certificates that you trust. =trustStore in tomcat
   ssl_client_certificate ca.pem;
   # this indicates whether client authentication is required, or optional (clientAuth="true" vs "want" in tomcat)
   ssl_verify_client on;

   location / {
      #proxy_pass configuration here, inclding X-Forwarded-For headers
      proxy_set_header X-Client-Certificate $ssl_client_cert;
   }
}

这样,客户端证书将作为标头转发( 如此处建议 )。 这看起来很像黑客,可能是因为黑客证书不是一个很小的字符串。 但这是我唯一能想到的方法。

但是,有一个小问题(对于Tomcat解决方案也是如此)–如果您为整个域启用客户端身份验证,则无法拥有完全不受保护的页面。 即使身份验证是可选的(“希望”),无论用户首先打开哪个页面,浏览器对话框(用户从中选择证书)都将被触发。 好处是,没有证书的用户仍然可以浏览未受代码明确保护的页面。 但是对于拥有证书的人,即使他可能不想进行身份验证,打开主页也会打开对话框。 有一些事情可以解决。

我实际上已经看到Perl“每页”完成了,但是我不确定这可以通过Java设置来完成。 好吧,如果您不使用servlet容器,而是自己处理TLS握手,则可以。 但这是不可取的。

通常,您只需要针对单个URL的浏览器身份验证对话框即可。 “ / login”,或者像我使用OpenID Connect实现MitreID的分叉 (“ / authenticate”端点)一样(用户被重定向到Identity Provider / authenticate URL,通常他必须在其中输入用户名/密码,但在这种情况下,他只需要选择适当的证书即可。 可以做的是从子域访问该特定端点。 这将意味着在nginx配置中还有另一个“服务器”部分,其中subodmain和ssl_verify_client on ,而常规域保持不变,无需任何客户端证书验证。 这样,将仅对对子域的请求进行身份验证。

现在,如何进行实际身份验证。 上面提到的OpenID Connect实现使用spring安全性,但是可以是任何东西。 我的实现支持上述两种情况(tomcat和nginx + tomcat)。 这使应用程序可以感知负载平衡器,但是您可以安全地选择一种或另一种方法,并从代码中除去另一半。

对于单一的tomcat方法,只需通过以下几行即可获得X509Certificate

X509Certificate certs[] = (X509Certificate[]) request
       .getAttribute("javax.servlet.request.X509Certificate");
    // check if not empty and get the first one

对于nginx-in-front方法,要复​​杂一些。 我们必须获取标头,将其转换为适当的状态,然后解析它。 (请注意,我不使用spring-security X509过滤器,因为它仅支持single-tomcat方法。)

String certificateHeader = 
    request.getHeader("X-Client-Certificate");
if (certificateHeader == null) {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    return;
}
// the load balancer (e.g. nginx) forwards the certificate 
// into a header by replacing new lines with whitespaces 
// (2 or more). Also replace tabs, which sometimes nginx 
// may send instead of whitespaces
String certificateContent = certificateHeader
     .replaceAll("\\s{2,}", System.lineSeparator())
     .replaceAll("\\t+", System.lineSeparator());
userCertificate = (X509Certificate) certificateFactory
    .generateCertificate(new ByteArrayInputStream(
        certificateContent.getBytes("ISO-8859-11")));

现在,“漏洞”很明显,因为nginx以一种方式发送了经过认证的PEM编码的证书。 幸运的是,行之间用某种空格隔开(一次是空格,另一次是制表符(在Windows计算机上)),因此我们可以将其还原为原始PEM格式(即使不必知道PEM行是64个字符)。 可能是其他版本的nginx或其他服务器没有放置空格,因此可能必须拆分成64个字符的行。 然后,我们使用X.509证书工厂创建证书对象。

基本上就是这样。 然后,我们可以使用此巧妙的“技巧”从证书中提取CN(通用名称)或任何其他唯一标识字段,并使用它从我们的数据库中加载相应的用户记录。

就是这样,或者至少是我从概念验证中得到的。 这是一个利基用例,而智能卡与计算机之间的通信很大是一个大可用性问题 ,但是对于国家安全的e-id方案,电子银行和内部应用程序来说,这可能不是一个坏主意。

翻译自: https://www.javacodegeeks.com/2015/12/tls-client-authentication.html

客户端 tls解密

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值