在Tomcat8上安装和配置SSL/TLS支持[官方版]
SSL / TLS简介
传输层安全性(TLS)及其前身安全套接字层(SSL)是允许Web浏览器和Web服务器通过安全连接进行通信的技术。这意味着所发送的数据在处理之前被一方加密,传送,然后由另一方解密。这是一个双向的过程,这意味着服务器和浏览器都会在发送数据之前对所有流量进行加密。
SSL / TLS协议的另一个重要方面是身份验证。这意味着,在您最初尝试通过安全连接与Web服务器进行通信时,该服务器将以“证书”的形式向您的Web浏览器显示一组凭据,以证明该网站是谁以及它声称的内容成为。在某些情况下,服务器也可能从您的网络浏览器请求证书,要求证明您是您自称的人。这就是所谓的“客户端认证”,尽管实际上这比企业到企业(B2B)交易更多地用于个人用户。大多数启用了SSL的Web服务器不会请求客户端身份验证。
SSL / TLS和Tomcat
需要注意的是,配置Tomcat利用安全套接字通常仅在将其作为独立Web服务器运行时才是必需的。详细信息可以在 安全注意事项文档中找到。当主要运行Tomcat作为另一个Web服务器(如Apache或Microsoft IIS)后面的Servlet / JSP容器时,通常需要配置主Web服务器来处理来自用户的SSL连接。通常,此服务器将协商所有与SSL相关的功能,然后只有在解密这些请求之后才传递任何发往Tomcat容器的请求。同样,Tomcat将返回明文响应,在返回给用户的浏览器之前将被加密。在这个环境中,Tomcat知道主Web服务器和客户端之间的通信是通过一个安全的连接进行的(因为你的应用程序需要能够询问这个),但是它本身并不参与加密或解密。
证书
为了实现SSL,Web服务器必须为每个接受安全连接的外部接口(IP地址)提供相关的证书。这个设计背后的理论是,服务器应该提供某种合理的保证,即它的所有者是你认为的那个人,特别是在收到任何敏感信息之前。虽然对证书的更广泛的解释超出了本文的范围,但将证书视为互联网地址的“数字护照”。它规定了该网站与哪个组织关联,以及关于网站所有者或管理员的一些基本联系信息。
这个证书是由其所有者加密签字的,因此对于其他人来说是非常困难的。要使证书在访问者浏览器中无警告地工作,需要由受信任的第三方签名。这些被称为证书颁发机构(CA)。要获得签名证书,您需要选择一个CA,并按照您选择的CA提供的说明获取您的证书。一系列的CA可用,包括一些免费提供证书。
Java提供了一个相对简单的命令行工具, keytool
可以方便地创建一个“自签名”的证书。自签名证书只是用户生成的证书,这些证书尚未由知名CA签署,因此根本不能保证真实。虽然自签名证书可以用于某些测试场景,但不适合任何形式的生产使用。
运行SSL的一般提示
使用SSL保护网站时,确保网站使用的所有资产都通过SSL提供服务非常重要,以便攻击者不能通过在JavaScript文件或类似内容中注入恶意内容来绕过安全性。为了进一步增强您的网站的安全性,您应该评估使用HSTS标头。它允许您与浏览器通信,您的网站应始终通过https访问。
在安全连接上使用基于名称的虚拟主机需要仔细配置单个证书中指定的名称,或者需要服务器名称指示(SNI)支持的Tomcat 8.5以上版本。SNI允许具有不同名称的多个证书与单个TLS连接器相关联。
步骤
要在Tomcat上安装和配置SSL / TLS支持,您需要遵循以下简单的步骤。有关更多信息,请阅读本“如何操作”的其余部分。
-
通过执行以下命令创建一个密钥库文件来存储服务器的私钥和自签名证书:
Windows:
"%JAVA_HOME%\bin\keytool" -genkey -alias tomcat -keyalg RSA
Unix的:
$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA
并指定密码值“changeit”。
-
取消对“SSL HTTP / 1.1连接器”条目的注释
$CATALINA_BASE/conf/server.xml
并按照下面的“ 配置”部分所述进行修改。
准备证书密钥库
Tomcat目前只能运行JKS
,PKCS11
或 PKCS12
格式化密钥库。该JKS
格式是Java的标准“Java密钥库”的格式,并且是由创建的格式 keytool
命令行实用程序。该工具包含在JDK中。该PKCS12
格式是一种Internet标准,并可以通过操纵(除其他事项外),OpenSSL和微软的密钥管理。
密钥库中的每个条目都由一个别名字符串标识。虽然许多密钥库实现以不区分大小写的方式处理别名,但区分大小写的实现是可用的。在PKCS11
说明书中,例如,要求的别名是大小写敏感的。为避免与别名区分大小写相关的问题,建议不要使用仅在大小写不同的别名。
要将现有证书导入JKS
密钥库,请阅读(在您的JDK文档包中)有关的文档keytool
。请注意,OpenSSL通常在密钥之前添加可读的注释,但 keytool
不支持。因此,如果您的证书在密钥数据之前有注释,请在导入证书之前将其删除 keytool
。
要PKCS12
使用OpenSSL 将由您自己的CA签名的现有证书导入到密钥库中,您需要执行如下命令:
openssl pkcs12 -export -in mycert.crt -inkey mykey.key
-out mycert.p12 -name tomcat -CAfile myCA.crt
-caname root -chain
有关更高级的情况,请查阅 OpenSSL文档。
要JKS
从头创建一个包含单个自签名证书的新密钥库,请从终端命令行执行以下操作:
视窗:
"%JAVA_HOME%\bin\keytool" -genkey -alias tomcat -keyalg RSA
Unix的:
$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA
(RSA算法应作为安全算法首选,这也确保了与其他服务器和组件的通用兼容性。)
这个命令会在你运行它的用户的主目录下创建一个新文件,命名为“ .keystore
”。要指定不同的位置或文件名,请将-keystore
参数(后跟密钥库文件的完整路径名)添加到keytool
上面显示的命令中。如后所述,您还需要在server.xml
配置文件中反映这个新位置。例如:
windows:
"%JAVA_HOME%\bin\keytool" -genkey -alias tomcat -keyalg RSA
-keystore \path\to\my\keystore
Unix的:
$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA
-keystore /path/to/my/keystore
执行完此命令后,您将首先被提示输入密钥库密码。Tomcat使用的默认密码是“ changeit
”(全部小写),尽管您可以指定自定义密码。您还需要在server.xml
配置文件中指定自定义密码 ,如后面所述。
接下来,系统会提示您提供有关此证书的一般信息,例如公司,联系人姓名等。此信息将显示给尝试访问应用程序中安全页面的用户,因此请确保此处提供的信息符合他们的期望。
最后,将提示您输入密钥密码,密钥是专用于此证书的密码(而不是存储在同一密钥库文件中的任何其他证书)。该keytool
提示会告诉你,按ENTER键会自动使用相同的密码密钥作为密钥库。您可以*使用相同的密码或选择一个自定义密码。如果您为密钥库密码选择不同的密码,则还需要在server.xml
配置文件中指定自定义密码。
如果一切顺利,您现在有一个密钥库文件,可以使用服务器使用的证书。
编辑Tomcat配置文件
Tomcat可以使用两种不同的SSL实现:
- 作为Java运行时的一部分提供的JSSE实现(自1.4开始)
- APR实现,默认情况下使用OpenSSL引擎。
确切的配置细节取决于正在使用哪个实现。如果通过指定generic来配置Connector, protocol="HTTP/1.1"
则自动选择Tomcat使用的实现。如果安装使用APR(即,您已经安装了Tomcat本机库),那么它将使用APR SSL实现,否则将使用Java JSSE实现。
由于支持SSL的配置属性在APR和JSSE实现之间有很大差异,因此建议避免自动选择实现。这是通过在连接器的协议属性中指定一个类名来完成的。
要定义Java(JSSE)连接器,无论是否加载APR库,请使用以下选项之一:
<!-- Define a HTTP/1.1 Connector on port 8443, JSSE NIO implementation -->
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8443" .../>
<!-- Define a HTTP/1.1 Connector on port 8443, JSSE NIO2 implementation -->
<Connector protocol="org.apache.coyote.http11.Http11Nio2Protocol"
port="8443" .../>
<!-- Define a HTTP/1.1 Connector on port 8443, JSSE BIO implementation -->
<Connector protocol="org.apache.coyote.http11.Http11Protocol"
port="8443" .../>
或者,要指定APR连接器(APR库必须可用),请使用:
<!-- Define a HTTP/1.1 Connector on port 8443, APR implementation -->
<Connector protocol="org.apache.coyote.http11.Http11AprProtocol"
port="8443" .../>
如果您正在使用APR,则可以选择配置OpenSSL的替代引擎。
<Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="someengine" SSLRandomSeed="somedevice" />
默认值是
<Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="on" SSLRandomSeed="builtin" />
因此,要在APR下使用SSL,请确保SSLEngine属性设置为非off
。默认值是on
,如果你指定另一个值,它必须是一个有效的引擎名称。
SSLRandomSeed允许指定熵的来源。生产系统需要一个可靠的熵源,但熵可能需要大量的时间来收集,因此测试系统可以使用“/ dev / urandom”这样的阻塞熵源,这将允许Tomcat更快的启动。
最后一步是在$CATALINA_BASE/conf/server.xml
文件中配置Connector ,其中 $CATALINA_BASE
表示Tomcat实例的基本目录。 Tomcat安装<Connector>
的默认server.xml
文件中包含SSL连接器的示例元素。要配置使用JSSE的SSL连接器,您需要删除注释并进行编辑,使其看起来像这样:
<!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector
protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="${user.home}/.keystore" keystorePass="changeit"
clientAuth="false" sslProtocol="TLS"/>
APR连接器对许多SSL设置使用不同的属性,特别是密钥和证书。APR配置的一个例子是:
<!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector
protocol="org.apache.coyote.http11.Http11AprProtocol"
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
SSLCertificateFile="/usr/local/ssl/server.crt"
SSLCertificateKeyFile="/usr/local/ssl/server.pem"
SSLVerifyClient="optional" SSLProtocol="TLSv1+TLSv1.1+TLSv1.2"/>
HTTP连接器配置参考的“SSL支持”部分记录了配置选项以及强制属性的信息 。确保您使用的连接器使用正确的属性。BIO,NIO和NIO2连接器使用JSSE,而APR /本机连接器使用APR。
该port
属性是Tomcat将监听安全连接的TCP / IP端口号。您可以将其更改为您希望的任何端口号(如https
通信的默认端口 ,即443)。但是,在许多操作系统上,需要特殊的设置(在本文档的范围之外)才能在低于1024的端口号上运行Tomcat。
如果您在此更改端口号,则还应更改redirectPort
为非SSL连接器上的属性指定的值。这允许Tomcat按照Servlet规范的要求,自动地重定向试图访问页面的用户,同时指定需要SSL的安全约束。
完成这些配置更改后,必须像平常一样重新启动Tomcat,并且应该开展业务。您应该可以通过SSL访问Tomcat支持的任何Web应用程序。例如,尝试:
https://localhost:8443/
你应该看到通常的Tomcat启动页面(除非你已经修改了ROOT web应用程序)。如果这不起作用,以下部分包含一些疑难解答提示。
从证书颁发机构安装证书
要从证书颁发机构(如verisign.com,thawte.com或trustcenter.de)获取并安装证书,请阅读前一部分,然后按照以下说明进行操作:
创建一个本地证书签名请求(CSR)
为了从您选择的证书颁发机构获得证书,您必须创建一个所谓的证书签名请求(CSR)。证书颁发机构将使用CSR来创建证书,将您的网站标识为“安全”。要创建CSR,请按照以下步骤操作:
-
创建一个本地自签证书(如上一节所述):
keytool -genkey -alias tomcat -keyalg RSA -keystore <your_keystore_filename>
www.myside.org
在“first-and lastname”字段中输入您的网站(即)的域名才能创建工作证书。 -
CSR随后创建:
keytool -certreq -keyalg RSA -alias tomcat -file certreq.csr -keystore <your_keystore_filename>
现在你有一个文件叫certreq.csr
你可以提交给证书颁发机构(查看证书颁发机构网站的文档,了解如何做到这一点)。作为回报你得到一个证书。
导入证书
现在你有了你的证书,你可以把它导入你本地的密钥库。首先,您必须将所谓的“链式证书”或“根证书”导入您的密钥库。之后,您可以继续导入您的证书。
-
从您获得证书的证书颁发机构下载证书链。
对于Verisign.com商业证书,请访问:http://www.verisign.com/support/install/intermediate.html
有关Verisign.com试用证书,请访问:http://www.verisign.com/support/verisign-intermediate -ca / Trial_Secure_Server_Root / index.html
对于Trustcenter.de,请
转到:http: //www.trustcenter.de/certservices/cacerts/en/en.htm#server 对于Thawte.com,请转到:http://www.thawte的.com /证书/ trustmap.html -
将链式证书导入您的密钥库
keytool -import -alias root -keystore <your_keystore_filename> -trustcacerts -file <filename_of_the_chain_certificate>
-
最后导入你的新证书
keytool -import -alias tomcat -keystore <your_keystore_filename> -file <your_certificate_filename>
故障排除
以下列出了设置SSL通信时可能遇到的常见问题,以及如何解决这些问题。
-
当Tomcat启动时,出现“java.io.FileNotFoundException:{some-directory} / {some-file} not found”异常。
一个可能的解释是,Tomcat找不到它所在的密钥库文件。默认情况下,Tomcat需要在
.keystore
运行Tomcat的用户主目录中命名密钥库文件(可能与您的:或不一样)。如果keystore文件位于其他任何地方,则需要向Tomcat配置文件中keystoreFile
的<Connector>
元素添加一个 属性。 -
当Tomcat启动时,我得到一个异常,如“java.io.FileNotFoundException:密钥库被篡改,或密码不正确”。
假设有人没有真正篡改密钥库文件,最可能的原因是Tomcat使用的密码与您在创建密钥库文件时使用的密码不同。要解决这个问题,您可以返回并 重新创建密钥库文件,也可以添加或更新Tomcat配置文件中元素 的
keystorePass
属性。 提醒 - 密码区分大小写!<Connector>
-
当Tomcat启动时,我得到一个异常,例如“java.net.SocketException:SSL握手错误javax.net.ssl.SSLException:没有可用的证书或密钥对应于启用的SSL密码套件”。
可能的解释是Tomcat无法在指定的密钥库中找到服务器密钥的别名。检查是否正确
keystoreFile
,并keyAlias
在指定<Connector>
的元素中的 Tomcat配置文件。 提示 -keyAlias
值可能区分大小写! -
我的基于Java的客户端异常终止握手,例如“java.lang.RuntimeException:无法生成DH密钥对”和“java.security.InvalidAlgorithmParameterException:素数大小必须是64的倍数,并且只能在512到1024之间)”
如果您使用的是APR /本地连接器,则从版本1.1.34开始,它将根据RSA证书的密钥大小确定临时DH密钥的强度。例如,一个2048位的RSA密钥将导致DH密钥使用2048位素数。不幸的是Java 6只支持768位,Java 7只支持1024位。因此,如果您的证书具有更强大的密钥,则旧的Java客户端可能会产生此类握手失败。作为一种缓解措施,您可以尝试强制他们使用另一种密码,方法是配置一个适当的密钥
SSLCipherSuite
并激活SSLHonorCipherOrder
,或者在您的证书文件中嵌入弱DH参数。不推荐使用后一种方法,因为它削弱了SSL的安全性(logjam攻击)。
如果你仍然有问题,一个好的信息来源是 TOMCAT-USER邮件列表。您可以在http://tomcat.apache.org/lists.html上找到指向此列表上先前消息的存档的指针,以及订阅和取消订阅信息 。
在应用程序中使用SSL进行会话跟踪
这是Servlet 3.0规范中的一个新特性。因为它使用与物理客户端 - 服务器连接关联的SSL会话标识,所以存在一些限制。他们是:
-
Tomcat必须有一个连接器,其属性 isSecure设置为
true
。 - 如果SSL连接由代理或硬件加速器管理,则必须填充SSL请求标头(请参阅 SSLValve),以便SSL会话标识对Tomcat可见。
- 如果Tomcat终止SSL连接,将不可能使用会话复制,因为SSL会话ID在每个节点上都不相同。
要启用SSL会话跟踪,您需要使用上下文侦听器将上下文的跟踪模式设置为SSL(如果启用了任何其他跟踪模式,则会优先使用)。它可能看起来像这样:
package org.apache.tomcat.example;
import java.util.EnumSet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.SessionTrackingMode;
public class SessionTrackingModeListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent event) {
// Do nothing
}
@Override
public void contextInitialized(ServletContextEvent event) {
ServletContext context = event.getServletContext();
EnumSet<SessionTrackingMode> modes =
EnumSet.of(SessionTrackingMode.SSL);
context.setSessionTrackingModes(modes);
}
}
注意:SSL会话跟踪是为BIO,NIO和NIO2连接器实现的。APR连接器尚未实施。
其他技巧和位
要从请求访问SSL会话ID,请使用:
String sslID = (String)request.getAttribute("javax.servlet.request.ssl_session_id");
有关这方面的更多讨论,请参阅 Bugzilla。
要终止SSL会话,请使用:
// Standard HTTP session invalidation
session.invalidate();
// Invalidate the SSL Session
org.apache.tomcat.util.net.SSLSessionManager mgr =
(org.apache.tomcat.util.net.SSLSessionManager)
request.getAttribute("javax.servlet.request.ssl_session_mgr");
mgr.invalidateSession();
// Close the connection since the SSL session will be active until the connection
// is closed
response.setHeader("Connection", "close");
请注意,由于使用了SSLSessionManager类,此代码是特定于Tomcat的。目前仅适用于BIO,NIO和NIO2连接器,而不是APR /本地连接器。