设置https

这第一小节的内容参考了文章:https://blog.csdn.net/freeiceflame/article/details/50420059

通常,在创建HTTPS的服务器的时候都需要一个网站的SSL证书文件,但是在网上找到的文档基本上都是在介绍怎么自己用keytools创建一个证书,但是这种方法申请的证书根本不会被广大网民的浏览器认证,所以想要创建一个大家都能访问的HTTPS服务,则从一个受信任的机构去申请一个证书。

 

而从认证网站上下载的证书中并不会包括TOMCAT可以使用的jks证书文件,那么必须要先将证书转换为TOMCAT可以使用的格式。假设我们现在已经从CA申请下来了证书文件,也有私钥文件:

1、example.com.crt:证书文件,里面已包含自己网站的证书和CA机构的中级证书

2、example.com.key:私钥文件

 

一、合并证书,生成PKCS12格式的temp.p12文件。会提示你创建密码(对应tomcat配置文件中的keyPass)。命令行输入:

openssl pkcs12 -export -in example.com.crt -inkey example.com.key -out temp.p12 -name temp

 

二、生成jks格式的keystore文件,这个格式的文件可以直接被tomcat识别。需要输入上一步创建的密码,及指定新的keystore密码(对应tomcat配置文件中的keystorePas):

keytool -importkeystore -srckeystore temp.p12 -srcstoretype PKCS12 -destkeystore example.com.jks

 

三、修改tomcat的server.xml中连接器(Connector)的配置,设置好后重启tomcat就启用https了:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11Protocol"

connectionTimeout="20000" redirectPort="8443"

SSLEnabled="true" scheme="https" secure="true" clientAuth="false"

sslProtocol="TLS" sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2"

keystoreFile="/home/test/tomcat/apache-tomcat-7.0.68/example.com.jks"

keyPass="changeit" keystorePass="npzd9zgk" />

  • protocol:设置用于处理流量的协议,这里使用的是BIO。详细解释见"Tomcat配置文件解析"小节。作为优化,可以考虑改为使用NIO或NIO2(如果支持的话),其它https的设置都是相同的。BIO/NIO/NIO2连接器都是依赖于JSSE SSL来实现https的。如果是使用APR协议的话,https的配置则不相同,见"设置https(APR连接器实现的)"小节。APR是依赖于OpenSSL来实现https的。

  • SSLEnabled:启用HTTPS。

  • scheme:可选值为http或https。程序中使用request.getScheme()方法时,会获取到scheme中指定的值,因此需要传递正确的值给程序。

  • secure:如果你希望对于该连接器接收到的请求,返回给request.isSecure()方法的调用为true,就设置该值为true。对于SSL连接器,或是正在从SSL加速器(如加密卡)、SSL应用或web服务器接收数据的非SSL连接器,你可能希望将该值设置为true。默认值为false。

  • clientAuth:设置是否对客户端进行HTTPS认证,详细说明见tomcat官网。默认为false。

  • sslProtocol:要使用的SSL协议。默认值是"TLS"。该属性与sslEnabledProtocols属性是重叠的。

  • sslEnabledProtocols:要使HTTPS支持的SSL协议。如果指定了该值,那么,只有这里列出的并且是SSL实施支持的协议才会被启用。如果未指定该值,JVM默认值会被使用。该属性与sslProtocol属性是重叠的。

  • keystoreFile:存储了服务器HTTPS证书的keystore文件的位置。可以使用绝对路径或相对路径(相对于CATALINA_BASE)。

  • keyPass:用于从指定的keystore文件访问服务器证书的密码。默认值是"changeit"。

  • keystorePass:用于访问指定keystore文件的密码。默认值是keyPass属性的值。

  • keystoreType:keystore文件类型。默认只是"JKS"。

  • ciphers:tomcat中加密套件的名称使用的是"JSSE cipher naming convention"的命名方式。如果使用关键字ALL,则可以启用所有加密套件,但这样可能是不安全的,所以仅用于测试。下面是经测试过的加密套件,可以保证安全性并兼容大多数客户端:

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,

TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA256,

TLS_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,

TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA

  • useServerCipherSuitesOrder:若设定为true,则会强制客户端按照Server端的加密套件顺序来选择适合的加密套件。仅在tomcat 8及以上版本才支持该选项。

 

设置https(APR连接器实现的)

1、如果按照"设置https"小节,那么搭建出来的https站点很可能是不兼容Java 6客户端的,那么,所有运行在JDK 6上的Java应用程序调用我们https站点的API接口时,都会失败。这个在https://www.ssllabs.com/网站上可以测试出来:

实际使用运行于Java 6的应用程序调用https站点时,会报类似"javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake"的错误信息。这并不是https站点使用的加密套件不兼容Java 6客户端的原因,而是https站点无法正确处理Java 6客户端的https握手消息。

 

2、为了解决上面的问题,我们需要使用APR连接器实现的https。APR是依赖于OpenSSL来实现https的,不仅从性能还是功能来说,APR连接器都会比BIO/NIO/NIO2连接器好。在给tomcat配置APR连接器之前,需要先安装APR和OpenSSL,见"APR的问题"小节。

 

3、修改tomcat的server.xml中连接器(Connector)的配置,设置好后重启tomcat:

   <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"

          connectionTimeout="20000" maxThreads="500"

          SSLEnabled="true" scheme="https" secure="true" clientAuth="false"

          SSLProtocol="TLSv1,TLSv1.1,TLSv1.2"

          SSLCertificateChainFile="/home/test/tomcat/apache-tomcat-7.0.68/CA.crt"

          SSLCertificateFile="/home/test/tomcat/apache-tomcat-7.0.68/example.com.crt"

          SSLCertificateKeyFile="/home/test/tomcat/apache-tomcat-7.0.68/example.com.key"

          SSLCipherSuite="ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA"

          SSLHonorCipherOrder="true" />

  • protocol:这里一定要使用APR连接器协议。下面的SSLProtocol、SSLCertificateFile、SSLCertificateKeyFile等配置都是仅适用于ARP实现的。

  • SSLProtocol:要支持的SSL协议。

  • SSLCertificateChainFile:包含中级CA证书的文件路径。证书文件是PEM编码格式的。

  • SSLCertificateFile:包含中级CA证书和网站本身的证书的文件路径。证书文件是PEM编码格式的。

  • SSLCertificateKeyFile:私钥文件的路径。私钥文件是PEM编码格式的。

  • SSLCipherSuite:加密套件。默认是"HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA"。

  • SSLHonorCipherOrder:若设定为true,则会强制客户端按照Server端的加密套件顺序来选择适合的加密套件。

 

上面有两个要注意的点:

1) SSLProtocol用于设定要支持的SSL协议。如果给基于OpenSSL的连接器指定超过一个协议,它就会总会支持SSLv2Hello;如果只指定了一个协议,它将不会支持SSLv2Hello。就是这个特性,使得ARP实现的https可以兼容Java 6客户端。

2) SSLCertificateChainFile指定的文件中只包含中级CA的证书,SSLCertificateFile指定的文件中既包含中级CA的证书也包含网站本身的证书(网站证书在文件中应该放在中级CA证书前面)。这里是与在nginx中配置https的情况不一样的。在tomcat中,需要同时指定SSLCertificateChainFile和SSLCertificateFile,否则证书链不完整。此时,使用浏览器来访问网站不会有报错,这可能是因为浏览器会自动下载中级CA的证书以构成完整的证书链。但是,如果使用Java客户端程序来调用https站点,可能就会出错,因为服务器提供的证书链是不完整的。SSLCertificateFile中既包含中级CA的证书也包含网站本身的证书,这是因为,像Java 6这种客户端它是不支持SNI(Server Name Indication)的,所以服务器必须一次性提供所有所需的证书给它,不然的话,若服务器提供的证书只包含网站本身的证书,它会认为证书无效。

 

4、最后的话,如果可能,到https://www.ssllabs.com/ssltest/上面测试下你的https站点,看有无问题。