0.背景知识
TLS/SSL握手的过程参考 SSL握手过程图解
1.常见报错
1.1 SSLHandshakeException handshake_failure
1.1.1 TLS/SSL协议版本不匹配
自从TLS 1.2版本在2008年发布以来,服务器处于安全性考虑通常也只支持较高版本TLS,比如TLS1.2及以上,如果这些客户端用低版本TLS/SSL向服务器发起握手,会因为服务器不支持而直接失败。
如JDK1.6就是用TLS1.0,访问使用TLS1.2的服务端就会报错,可以升级JDK1.8,默认使用1.2
1.1.2 cipher suite加密算法套件不匹配
服务器出于安全性考虑通常只会支持安全性较高的cipher,所以当客户端发过去的cipher suite安全性都比较低时会造成协商握手失败。
1.2 证书问题
1.2.1.客户端Bad Certificate
双向认证,不仅客户端要验证服务器证书,服务器也需要验证客户端证书。在服务器验证客户端证书的过程中,由于客户端证书证书链校验不通过,可能会直接产生Fatal Alert,导致握手直接中断。
解决方案:使用著名CA签发(如CFCA等)的客户端证书,如果可联系服务端开发可直接将自己的客户端证书放置在其信任列表汇总。
1.2.2 服务端 Certificate Validation
认证服务端证书如果证书链的最后一跳,不在客户端的信任证书列表,则会报证书校验不通过,此时需要手动加入服务端证书到信任证书列表,或者设置永久信任。Java实现,可以通过实现SSLContext等API,具体可以百度~
1.3 SSLException: Received fatal alert: internal_error
1.3.1 无法提取SNI导致TLS/SSL握手失败
在某些场景中,需要获取ClientHello中的SNI字段来作为一个必要条件, 比如用NGINX stream对HTTPS流量做4层代理时。客户端ClientHello中没有携带SNI,则会造成一个通过代理握手失败的局面。
在利用NGINX stream做正向代理时,NGXIN服务器需要获取客户端想要访问的目的域名。利ngx_stream_ssl_preread_module模块在不解密的情况下拿到ClientHello报文中SNI才能实现代理的正常功能。