很久之前开发的一套Java Web系统,该系统是企业内部使用的系统, 部署在Tomcat上,一开始使用http 访问, 后来因为安全需求, 转换为https 访问。
在几年前https 访问之后一切正常, 但是随着Chrome的升级, 使用Chrome 访问之后出现如下错误:
Your connection is not fully secureThis site uses an outdated security configuration, which may expose your information (for example, passwords, messages, or credit cards) when it is sent to this site.NET::ERR_SSL_OBSOLETE_VERSION
连接不是完全安全的, 提示的是已经废除的SSL 协议。 下面就解决这个问题为契机, 一步步对tomcat 7 配置https 进行讲解。
环境JDK版本:jdk1.6.0_30Tomcat 版本: Tomcat 7.0.57 配置步骤
这里假设应用的名称是 myapp
在应用的服务器端生成私钥库文件(.keystore)和证书申请文件(.csr)keytool -keysize 2048 -genkey -alias myapp -keyalg RSA -keystore myapp.keystorekeytool -certreq -keyalg RSA -alias myapp -file myapp.csr -keystore myapp.keystore
各命令选项意义如下:
-genkey 生成密钥-alias 别名-keysize 密钥长度-keystore 生成密钥库的路径和名字-keyalg 密钥算法-certreq 生成密钥请求文件
.keystore 是密钥库文件的后缀, .csr是证书申请文件(Certificate Signing Request )的后缀。
以上两个命令执行后, 会要求输入密码,单位,城市等一般信息。(注意这里设置的密码要记住)
first and last name : Unit : Organization: City:Privince: cn
以上两个命令最终会生成两个文件 : myapp.keystore 和 myapp.csr 。
将myapp.keystore 和 myapp.csr 提供给企业内部的CA部门,其签名之后,返回.cer和.p7b 两种格式的签名文件,对应base64 和 der 两种编码方式, 总共返回四个文件。 certnew_base64.cercertnew_base64.p7bcertnew_der.cercertnew_der.p7b 导入签名后的证书
以上四个文件选择一个就可以了,这里选择 certnew_base64.cer, 通过 keytool -import 命令将签名后的证书导入到密钥库文件 myapp.keystore
keytool -import -trustcacerts -alias myapp -file certnew_base64.cer -keystore myapp.keystore -storepass mypass
在Tomcat 中配置证书库修改tomcat安装目录的 conf/server.xml 文件。https 的配置如下:
443 是默认端口, 也就是在浏览器访问的时候可以直接使用机器名或是域名访问。配置其他端口需要加端口访问keystoreFile 设置的是导入签名证书后的证书库文件, 一般可以设置路径加文件名
到这里, 重启tomcat 之后,在Chrome访问该站点,地址栏前面的锁就是正常显示了, 如下图:
如果您的站点到这里一切正常,后面的部分就可以省略了、
Chrome 升级之后的问题 Chrome 持续发布版本, 对安全性要求也越来越高了。在96, 97(Version 97.0.4692.99)版本中, 已经要求服务端的协议是TLSv1.2, 所以如果服务器不支持TLSv1.2协议, 则在访问的时候就会 ERR_SSL_OBSOLETE_VERSION 的提示, 也就是SSL的协议版本太低了, 以及废弃了。
TLSv1.2 早期的协议版本有 TLSv1.1 ,TLSv1.0, 以及SSL系列的协议。
针对该处场景,出现ERR_SSL_OBSOLETE_VERSION可能性有两种:
先来看结论:
Tomcat 从 7 版本开始已经支持 TLSv1.2协议了, JDK从 1.6.121 开始支持 TLSv1.2。
JDK支持的TLS协议的版本, 可以通过代码获取:
@Test public void sslPro() throws Exception { SSLContext sslContext = SSLContext.getInstance("SSL"); X509TrustManager x509m = new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } }; sslContext.init(null, new TrustManager[] { x509m }, new java.security.SecureRandom()); SSLEngine e = sslContext.createSSLEngine(); System.out.println(Arrays.asList(e.getSupportedProtocols())); }
JDK1.6.0_30 输出 : [SSLv2Hello, SSLv3, TLSv1]JDK 1.6.121之上 版本输出: [SSLv2Hello, SSLv3, TLSv1, TLSv1.1, TLSv1.2]
也就是低版本的JDK是不支持TLSv1.2 的。 Tomcat 中设置限定使用TLSv1.2
Tomcat 7 可以设置使用TLSv1.2协议, 方式就是在
也就是说, 启用的SSL协议的版本是TLSv1.2 。
所以这里的解决方案是:
升级JDK版本到 JDK 1.6.121 之上, 这里升级到 1.7.0_80。
因为应用中的代码的限制, 不能升级跳跃太大。Java官方提供的1.6版本的下载地址是:
https://www.oracle.com/java/technologies/javase-java-archive-javase6-downloads.html
但是这个地址中找不到JDK 1.6.121的版本, 最大的版本是 6u45 , 也就是JDK 1.6.45。所以只能考虑升级到 1.7 。
修改 tomcat 的 conf/server.xml , 配置证书,以及协议:
这里配置了relaxedPathChars 和 relaxedQueryChars属性的原因是升级了tomcat 版本, 在新版本的tomcat中, 对安全性也做了提升, 不允许在访问地址中使用 |{}[] 这些符号, 也就是说, 如果是在请求地址中使用JSON格式传递参数的话, 是不允许的, 会报 The valid characters are defined in RFC 7230 and RFC 3986错误,添加这两个属性就是暂时放行。 提示
如果不升级JDK, 在tomcat 配置 sslEnabledProtocols="TLSv1.2", 会报找不到协议的错误 参考
JDK 从6u121 支持TLS1.2 https://www.oracle.com/java/technologies/javase/6u121-relnotes.htmlJDK 的版本对SSLTLS支持的版本: https://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#jssenames