查看jdk支持的密码套件:
package cn.zeh.test; import javax.net.ssl.SSLServerSocketFactory; import java.time.Clock; import java.util.Map; import java.util.TreeMap; public class Test { public static void main(String[] args) { getcipher(); } public static void getcipher() { SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); TreeMap<String, Boolean> ciphers = new TreeMap<String, Boolean>(); for (String cipher : ssf.getSupportedCipherSuites()) ciphers.put(cipher, Boolean.FALSE); String[] defaultCipherSuites = ssf.getDefaultCipherSuites(); for (String str : defaultCipherSuites) { System.out.println("defaultCipherSuites==" + str); } for (String cipher : defaultCipherSuites) ciphers.put(cipher, Boolean.TRUE); System.out.println("Default Cipher"); for (Map.Entry<String, Boolean> cipher : ciphers.entrySet()) { System.out.printf("%-5s%s%n", (cipher.getValue() ? '*' : ""), cipher.getKey()); } } }
本例是jdk1.8没有配置jce包,所以支持的加密算法不多,配置完后所有的加密算法都能支持
运行后:
"J:\Program Files\Java\jdk1.8.0_131\bin\java.exe" "-javaagent:J:\Program Files\ideaIU-2019.3.3.win\lib\idea_rt.jar=2157:J:\Program Files\ideaIU-2019.3.3.win\bin" -Dfile.encoding=UTF-8 -classpath "J:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;J:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;D:\ideaws\Test\out\production\Test" cn.zeh.test.Test defaultCipherSuites==TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 defaultCipherSuites==TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 defaultCipherSuites==TLS_RSA_WITH_AES_128_CBC_SHA256 defaultCipherSuites==TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 defaultCipherSuites==TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 defaultCipherSuites==TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 defaultCipherSuites==TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 defaultCipherSuites==TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA defaultCipherSuites==TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA defaultCipherSuites==TLS_RSA_WITH_AES_128_CBC_SHA defaultCipherSuites==TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA defaultCipherSuites==TLS_ECDH_RSA_WITH_AES_128_CBC_SHA defaultCipherSuites==TLS_DHE_RSA_WITH_AES_128_CBC_SHA defaultCipherSuites==TLS_DHE_DSS_WITH_AES_128_CBC_SHA defaultCipherSuites==TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 defaultCipherSuites==TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 defaultCipherSuites==TLS_RSA_WITH_AES_128_GCM_SHA256 defaultCipherSuites==TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 defaultCipherSuites==TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 defaultCipherSuites==TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 defaultCipherSuites==TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 defaultCipherSuites==TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA defaultCipherSuites==TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA defaultCipherSuites==SSL_RSA_WITH_3DES_EDE_CBC_SHA defaultCipherSuites==TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA defaultCipherSuites==TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA defaultCipherSuites==SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA defaultCipherSuites==SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA defaultCipherSuites==TLS_EMPTY_RENEGOTIATION_INFO_SCSV Default Cipher SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA * SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_DES_CBC_SHA SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA * SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_RSA_WITH_DES_CBC_SHA SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA SSL_DH_anon_WITH_3DES_EDE_CBC_SHA SSL_DH_anon_WITH_DES_CBC_SHA SSL_RSA_EXPORT_WITH_DES40_CBC_SHA * SSL_RSA_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_DES_CBC_SHA SSL_RSA_WITH_NULL_MD5 SSL_RSA_WITH_NULL_SHA * TLS_DHE_DSS_WITH_AES_128_CBC_SHA * TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 * TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 * TLS_DHE_RSA_WITH_AES_128_CBC_SHA * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_DH_anon_WITH_AES_128_CBC_SHA TLS_DH_anon_WITH_AES_128_CBC_SHA256 TLS_DH_anon_WITH_AES_128_GCM_SHA256 * TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_NULL_SHA * TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_NULL_SHA * TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 * TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDH_ECDSA_WITH_NULL_SHA * TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 * TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDH_RSA_WITH_NULL_SHA TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA TLS_ECDH_anon_WITH_AES_128_CBC_SHA TLS_ECDH_anon_WITH_NULL_SHA * TLS_EMPTY_RENEGOTIATION_INFO_SCSV TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA TLS_KRB5_WITH_3DES_EDE_CBC_MD5 TLS_KRB5_WITH_3DES_EDE_CBC_SHA TLS_KRB5_WITH_DES_CBC_MD5 TLS_KRB5_WITH_DES_CBC_SHA * TLS_RSA_WITH_AES_128_CBC_SHA * TLS_RSA_WITH_AES_128_CBC_SHA256 * TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_NULL_SHA256 Process finished with exit code 0
2,遇到javax.net.ssl.SSLHandshakeException: No appropriate protocol...这种异常,一般的解决办法就两步
配置之前可使用jvm ssl debug 参数查看ssl debug信息:
-Dssl.debug=true -Djavax.net.debug=all
1,查看是否配置了JCE
2, 是否启用了SSLV3,TLSv1,TLSv1.1等协议,启用方式为,删除掉 jre/lib/security/java.security文件中的 jdk.tls.disabledAlgorithms 的SSLV3,TLSv1,TLSv1.1,来开启对前面三种协议的支持
3,spring boot项目实现HTTPS单向认证&TLS指定加密套件
参考:https://blog.csdn.net/HD243608836/article/details/118708843
HTTPS 原理:
HTTPS协议 = HTTP协议 + SSL/TLS协议,在HTTPS数据传输的过程中,需要用SSL/TLS对数据进行加密和解密,需要用HTTP对加密后的数据进行传输,由此可以看出HTTPS是由HTTP和SSL/TLS一起合作完成的。
SSL的全称是Secure Sockets Layer,即安全套接层协议,是为网络通信提供安全及数据完整性的一种安全协议。SSL协议在1994年被Netscape发明,后来各个浏览器均支持SSL,其最新的版本是3.0
TLS的全称是Transport Layer Security,即安全传输层协议,最新版本的TLS(Transport Layer Security,传输层安全协议)是IETF(Internet Engineering Task Force,Internet工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本。在TLS与SSL3.0之间存在着显著的差别,主要是它们所支持的加密算法不同,所以TLS与SSL3.0不能互操作。虽然TLS与SSL3.0在加密算法上不同,但是在我们理解HTTPS的过程中,我们可以把SSL和TLS看做是同一个协议。
HTTPS为了兼顾安全与效率,同时使用了对称加密和非对称加密。数据是被对称加密传输的,对称加密过程需要客户端的一个密钥,为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输,总的来说,对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输。
常见的对称加密算法有DES、3DES、TDEA、Blowfish、RC5和IDEA。
在非对称加密中使用的主要算法有:RSA、Elgamal、Rabin、D-H、ECC(椭圆曲线加密算法)等。
这张图很经典
HTTPS在传输的过程中会涉及到三个密钥:
- 服务器端的公钥和私钥,用来进行非对称加密
- 客户端生成的随机密钥,用来进行对称加密
一个HTTPS请求实际上包含了两次HTTP传输,可以细分为8步。
- 客户端向服务器发起HTTPS请求,连接到服务器的443端口。
- 服务器端有一个密钥对,即公钥和私钥,是用来进行非对称加密使用的,服务器端保存着私钥,不能将其泄露,公钥可以发送给任何人。
- 服务器将自己的公钥发送给客户端。
- 客户端收到服务器端的公钥之后,会对公钥进行检查,验证其合法性,如果发现发现公钥有问题,那么HTTPS传输就无法继续。严格的说,这里应该是验证服务器发送的数字证书的合法性,关于客户端如何验证数字证书的合法性,下文会进行说明。如果公钥合格,那么客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,我们将该密钥称之为client key,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。然后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS中的第一次HTTP请求结束。
- 客户端会发起HTTPS中的第二个HTTP请求,将加密之后的客户端密钥发送给服务器。
- 服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文。
- 然后服务器将加密后的密文发送给客户端。
- 客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样HTTPS中的第二个HTTP请求结束,整个HTTPS传输完成。
数字证书
通过观察HTTPS的传输过程,我们知道,当服务器接收到客户端发来的请求时,会向客户端发送服务器自己的公钥,但是黑客有可能中途篡改公钥,将其改成黑客自己的,所以有个问题,客户端怎么信赖这个公钥是自己想要访问的服务器的公钥而不是黑客的呢? 这时候就需要用到数字证书。
在讲数字证书之前,先说一个小例子。假设一个镇里面有两个人A和B,A是个富豪,B想向A借钱,但是A和B不熟,怕B借了钱之后不还。这时候B找到了镇长,镇长给B作担保,告诉A说:“B人品不错,不会欠钱不还的,你就放心借给他吧。" A听了这话后,心里想:“镇长是全镇最德高望重的了,他说B没问题的话那就没事了,我就放心了”。 于是A相信B的为人,把钱借给了B。
与此相似的,要想让客户端信赖公钥,公钥也要找一个担保人,而且这个担保人的身份必须德高望重,否则没有说服力。这个担保人的就是证书认证中心(Certificate Authority),简称CA。 也就是说CA是专门对公钥进行认证,进行担保的,也就是专门给公钥做担保的担保公司。 全球知名的CA也就100多个,这些CA都是全球都认可的,比如VeriSign、GlobalSign等,国内知名的CA有WoSign。
那CA怎么对公钥做担保认证呢?CA本身也有一对公钥和私钥,CA会用CA自己的私钥对要进行认证的公钥进行非对称加密,此处待认证的公钥就相当于是明文,加密完之后,得到的密文再加上证书的过期时间、颁发给、颁发者等信息,就组成了数字证书。
不论什么平台,设备的操作系统中都会内置100多个全球公认的CA,说具体点就是设备中存储了这些知名CA的公钥。当客户端接收到服务器的数字证书的时候,会进行如下验证:
首先客户端会用设备中内置的CA的公钥尝试解密数字证书,如果所有内置的CA的公钥都无法解密该数字证书,说明该数字证书不是由一个全球知名的CA签发的,这样客户端就无法信任该服务器的数字证书。
如果有一个CA的公钥能够成功解密该数字证书,说明该数字证书就是由该CA的私钥签发的,因为被私钥加密的密文只能被与其成对的公钥解密。
除此之外,还需要检查客户端当前访问的服务器的域名是与数字证书中提供的“颁发给”这一项吻合,还要检查数字证书是否过期等。
通过浏览器直接获取服务器的公钥很容易,各个浏览器操作大同小异。百度现在已经实现了全站点HTTPS,我们就以百度为例如何从Chrome中获取其公钥。
1,用Chrome打开百度首页,在https左侧我们会发现有一个绿色的锁头。
2,点击该锁头,出现一个弹出面板,点击面板中的“详细信息”几个字。
3,这是会打开Chrome的Developer Tool,并自动切换到Security这个页面。
4,点击“View ceertificate”按钮就可以查看该网站的证书了,如下所示:
在“常规”这个面板中,我们从中可以查看该证书是又Symantec颁发给baidu.com这个网站的,有效期是从2015年9月17到2016年9月1日。
5,切换到“详细信息”面板,可以查看证书的一些详细信息,比如证书所使用的数字签名的算法,如下图所示:
上面有个“复制到文件”的按钮,点击该按钮就可以将百度的数字证书导出成文件,从而我们就可以保存到自己的机器上,界面如下所示:
我们将其导出成X.509格式的证书,以.cer作为文件扩展名,最后保存到本地机器如下所示:
6,切换到“证书路径”面板,可以查看证书的证书链。
这里先解释一下什么是证书链。我们之前提到,VeriSign是一个全球知名的CA,但是一般情况下,CA不会用自己的私钥去直接签名某网站的数字证书,一般CA会首先签发一种证书,然后用这种证书再去签发百度等的数字证书。在此例中,VeriSign签发了Symantec证书,然后Symantec又签发了baiduc.om,VeriSign位于最顶端,类似于根结点,因此叫做根CA,Symatec位于中间,叫做中间CA,当然,有可能有多个中间CA,这样从根CA到中间CA,再到最终的网站的证书,这样自上而下形成了一条证书链。如果想要查看证书链中的某个证书,只需要选中它,比如选中了Symantec,然后点击下面的“查看证书”按钮就会弹出另一个对话框,在其中可以查看Symantec的数字证书,当然也可以将其导出成证书文件保存在硬盘上。
参考文档: