我正在尝试在两个tomcat服务器之间使用https。不幸的是,自签名证书导致此错误:
Caused by: javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
具体来说,我有一个主tomcat和许多从属tomcat服务器。主机使用简单的HttpURLConnection从Servlet进行通信。
使用我自己的自行生成的证书颁发机构创建自签名证书的最简单方法是什么,这样,每次添加新服务器时,都不需要更改主tomcat服务器。
我可以使用openssl和java 7 keytool
作为参考,我之前的配置:
server.xml连接器:
<Connector port="443" maxHttpHeaderSize="8192" maxThreads="150"
minSpareThreads="25" maxSpareThreads="75" enableLookups="false"
disableUploadTimeout="true" acceptCount="100" debug="0" scheme="https"
secure="true" clientAuth="false" sslProtocol="TLS" keystoreType="PKCS12"
keystoreFile="/usr/java/apache-tomee-plus/conf/keystore.ks"
keystorePass="XXX_SSL" truststoreType="JKS"
truststoreFile="/usr/java/apache-tomee-plus/conf/truststore.ks"
SSLEnabled="true" maxPostSize="0"/>
启动脚本/etc/init.d/tomee
$DAEMON_HOME/jsvc \
-user $TOMCAT_USER \
-home $JAVA_HOME \
-pidfile $JSVC_PID_FILE \
-Dcatalina.home=$CATALINA_HOME \
-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.conf \
-Djavax.net.ssl.keystore=$CATALINA_HOME/conf/keystore.ks \
-Djavax.net.ssl.keyStorePassword=XXX_SSL \
-Djavax.net.ssl.trustStore=$CATALINA_HOME/conf/truststore.ks \
-Djavax.net.ssl.trustStorePassword=changeit \
-Djava.awt.headless=true \
-Djava.io.tmpdir=$TMP_DIR \
-Dopenam.agents.bootstrap.dir=/home/tomcat/tomcat_v6_agent/Agent_001/config \
-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses \
-outfile $CATALINA_HOME/logs/catalina.out \
-errfile $CATALINA_HOME/logs/catalina.err \
$CATALINA_OPTS \
-cp $CLASSPATH \
org.apache.catalina.startup.Bootstrap
conf / jaas.conf
josso {
org.josso.tc55.agent.jaas.SSOGatewayLoginModule required debug=true;
};
哪些仅用于旧版支持,并将逐步淘汰。我不确定它是否加载,因为它是为tomcat 5.5构建的。
在代码中,我通过使用以下HostnameVerifier()避免了在CN =中使用IP地址的问题。
HostnameVerifier hv = new HostnameVerifier()
{
public boolean verify(String urlHostName, SSLSession session)
{
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
connection = (HttpURLConnection) servlet.openConnection();
------------更新---------------
通过与@Bruno进行的长时间讨论已解决了此问题,请使用他的原始帖子以及我们进行的长时间聊天讨论。
最后,我使用了Keytool Explorer和XCA工具,使我更容易学习和执行。
最佳答案
首先,您实际上并没有建立服务器到服务器的连接:这些仍然是客户端到服务器的连接。碰巧您的客户端是在servlet容器中运行的webapp。
这很重要,因为将使用客户端信任设置来建立连接。这些与Tomcat连接器上的信任设置不同。
客户端Web应用程序如何使用其信任设置取决于其实现方式以及所使用的库。可以公平地说,大多数客户端将使用默认的JRE设置,除非有特定的代码可以这样做。没有任何设置,通常将使用JRE的cacerts
文件(请参见JSSE Reference guide, customisation section中的详细信息)。您还可以指定常用的javax.net.ssl.*
属性(使用-Djavax.net.ssl....=....
);这需要在.bat
中的catalina启动脚本文件(.sh
或JAVA_OPTS
取决于平台)中完成。这将影响在此JRE实例中运行的默认值,因此,它不是您的首选(您可能希望更具体的内容仅影响给定的Webapp,但您需要知道该Webapp的实现方式或可能的选项它可以使用)。不过,<Connector .../>
中的设置将覆盖此设置(并且那里的信任库设置无关紧要,除非您也要使用客户端证书身份验证)。
如果您有许多系统,那么使用自签名证书可能不值得:每个客户端都需要将所有这些自签名证书导入其信任存储区。相反,您可以创建自己的CA并仅导入该CA证书。 (在本地部署中,单个顶级/根CA应该足够,而无需中间CA。)OpenSSL的CA.pl
是构建小型CA的好脚本,但是您可能会发现其他工具,例如XCA或TinyCA更方便。 (请注意,通常可以使用.p12
密钥库类型而不是默认的JKS直接在Java中直接使用PKCS12
文件。对于PKCS#12存储库,密钥库密码和密钥/密钥管理器密码相同。)
由于您使用的是IP地址而不是名称,因此还应该注意Java follows RFC 2818 on IP address quite stricly(与许多浏览器不同)。特别是,您的主题DN的CN中的IP地址将不起作用:它必须在主题备用名称扩展名中(类型为IPAddress,而不是DNSname)。
编辑:
首先,摆脱该主机名验证程序:它为所有将使用该默认验证程序的HttpsURLConnection
引入MITM攻击漏洞,包括可能与外部服务器的连接。您可以使用SAN的IP地址来解决此问题。
这是您需要遵循的步骤:
创建您的CA(例如,使用XCA)。将其证书(不是其私钥)导出到mycacert.pem
。
如果您的应用程序可能与其他服务建立HTTPS连接,请将默认的cacerts
文件复制到新文件mytruststore.jks
中(如果您的应用程序未进行任何其他连接,请不要复制该文件,keytool
将创造它)。
用mycacert.pem
将mytruststore.jks
导入到keytool
中:
keytool -import -keystore mytruststore.jks -alias my_alias_name -cert mycacert.pem
现在,您有了一个信任库,可以将其安装在所有需要与这些服务器通信的客户端中。 (如果
cacerts
文件已通过JRE更新,则可能需要再次执行这些步骤。)在客户端中配置该信任库。在这里,这是在您的Catalina脚本中的
JAVA_OPTS
:-Djavax.net.ssl.trustStore=...
(和密码)中完成的。除了这些JVM选项严格在Catalina启动中的事实之外,它们与其他类型的客户端相同。摆脱
-Djavax.net.ssl.keyStore=...
那里,这将仅用于客户端证书身份验证,让webapp使用运行它们的服务器的证书进行客户端身份验证并非总是一个好主意。为要使用的每个服务器创建带有该CA的证书。如果要使用IP地址,请确保使用IP地址SAN。 (由于您可以控制一切,因此XCA应该允许您一步生成私钥和证书,这里不需要CSR,但是您可以这样做。它还为Web服务器扩展准备了配置文件,例如以及添加IP地址或其他类型的使用者备用名称的选项。)
将证书和私钥的组合导出到每个服务器的PKCS#12(例如
server1.p12
)中。每个服务器应该有自己的,不要共享。您将可以在每个服务器配置中将其用作"keystore keystore"。在连接器配置中的每台服务器中配置这些密钥库(使用PKCS#12存储时,
keystoreType="PKCS12",
,keyPass
和keystorePass
应该相同)。除非您使用客户端证书身份验证,否则在连接器配置中实际上不需要任何信任库设置。
(可能值得使用客户端证书身份验证来确保与服务器的连接至少仅来自同一CA的另一个实体,没有更精确的定义,但是您在连接器上配置的信任库将需要包含仅您的CA证书,而不是其他证书,因此为此创建一个全新的信任库。)
关于java - 如何在两个tomcat之间使用https时创建两个Tomcat满意的自签名证书?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21859371/