[英]Find or initialize the keystore needed to solve “hostname in certificate didn't match”
I recently inherited a lab Ubuntu LAMP server that has been relatively neglected and still running a Struts 1.0 application. 我最近继承了一个实验室的Ubuntu LAMP服务器,该服务器相对被忽略了,并且仍在运行Struts 1.0应用程序。 We are preping for a complete overhaul, but in the mean time the only error that is being thrown in the logs is a
javax.net.ssl.SSLException: hostname in certificate didn't match
error. 我们正在准备进行彻底的检查,但是与此同时,日志中抛出的唯一错误是
javax.net.ssl.SSLException: hostname in certificate didn't match
错误。 It's our hope to patch this temporarily while we write the replacement. 我们希望在编写替换内容时临时对此进行修补。 I've read several SO questions on the mater (eg 1 , 2 , 3 , 4 ) and it seemed like Will Sargent's solution was the best choice.
我读过一些等等母校问题(如1 , 2 , 3 , 4 ),它似乎像威尔·萨金特的解决方案是最好的选择。
Unfortunately I'm going into the server with utterly no documentation or returned email from the group that set it up (luckily none of the Java was obfuscated per policy). 不幸的是,我进入服务器时没有任何文档,也没有返回来自设置该服务器的小组的电子邮件(幸运的是,每个策略都没有混淆Java)。 I looked for any keystore files (searching for "keystore" in the file name or
.jks
files), but I didn't find any. 我寻找了任何密钥库文件(在文件名或
.jks
文件中搜索“ keystore”),但没有找到任何文件。 Which lead me think that I needed to make a new one and initialize it prior to calling the webClient.getPage
. 这导致我认为我需要制作一个新的并且在调用
webClient.getPage
之前对其进行初始化 。 So far I have been able to make the .jks
file just fine, it's just it doesn't change the hostname
match error. 到目前为止,我已经能够使
.jks
文件正常,只是它不会更改hostname
匹配错误。
Is there a way to see what keystore if any is being used by a servlet, and what its location happens to be? 有没有办法查看servlet正在使用什么密钥库,以及它的位置是什么? Alternatively, what is the proper way to make a new one and have it be used/initialized?
另外,制作一个新的并且被使用/初始化的正确方法是什么?
There are a few things about this that are odd to me. 关于这一点,我有些奇怪。 The main one is I don't understand why the hostname wouldn't be correct.
最主要的是我不明白为什么主机名不正确。 The site being pulled is
https://www.ncbi.nlm.nih.gov/account/
which if you navigate to it in a browser certainly pulls the correct certificate. 要提取的站点是
https://www.ncbi.nlm.nih.gov/account/
,如果您在浏览器中导航到该站点,则肯定会提取正确的证书。 I'm wondering if it's because the WebClient(BrowserVersion.FIREFOX_17)
is set to the archaic FIREFOX_17
. 我想知道是否是因为
WebClient(BrowserVersion.FIREFOX_17)
设置为FIREFOX_17
。 Should I just change that from 17 to 31? 我应该将其从17更改为31吗? There are plenty of things that could be upgraded, but as we're going to start from scratch to have documentation, I want to change as little as possible on the old instance to hopefully keep it running for a few more months.
有很多事情可以升级,但是随着我们从头开始编写文档,我希望对旧实例进行尽可能少的更改,以期使其运行几个月。 The FIREFOX version installed on the server isn't close to current ether (not that it's used), but I was thinking changing the
BrowserVersion
just changed how the reply was formatted. 安装在服务器上的FIREFOX版本与当前的以太
BrowserVersion
并不接近(不是使用它),但是我当时想更改BrowserVersion
只是改变了回复的格式。
Here is the code, ending on the line throwing the error: 这是代码,在引发错误的行上结束:
private Vector updateRDLpubs(Vector orderList, DataSource dataSource)
throws Exception
{
Vector removeList = new Vector();
Vector historyList = new Vector();
try
{
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
Calendar cal = Calendar.getInstance();
cal.add(5, -5);
Date days5Back = cal.getTime();
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_17);
webClient.setThrowExceptionOnFailingStatusCode(false);
HtmlPage page = (HtmlPage)webClient.getPage("https://www.ncbi.nlm.nih.gov/account/");
And here is the stack trace on the error: 这是关于错误的堆栈跟踪:
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:227)
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:147)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at com.gargoylesoftware.htmlunit.HtmlUnitSSLSocketFactory.connectSocket(HtmlUnitSSLSocketFactory.java:171)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:645)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:480)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:172)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1486)
at com.gargoylesoftware.htmlunit.WebClient.loadWebResponse(WebClient.java:1403)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:305)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:374)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:359)
at tanklab.UpdateRDLJob2.updateRDLpubs(UpdateRDLJob2.java:241)
at tanklab.UpdateRDLJob2.execute(UpdateRDLJob2.java:79)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
EDIT : Ahh, you are using HTMLUnit. 编辑 :啊,您正在使用HTMLUnit。 Your problem is probably that your HTMLUnit is severely out of date -- check against the server using https://tersesystems.com/2014/03/31/testing-hostname-verification/ and then upgrade HTMLUnit to the latest if nothing shows up.
您的问题可能是您的HTMLUnit已严重过时-使用https://tersesystems.com/2014/03/31/testing-hostname-verification/检查服务器,然后将HTMLUnit升级到最新(如果没有显示) 。
MORE EDIT : Why is HTMLUnit being used from Quartz? 更多编辑 :为什么从Quartz使用HTMLUnit? Are they trying to use it as a general HTTP Client?
他们是否正在尝试将其用作常规HTTP客户端? It's not designed for that.
它不是为此设计的。
The best reference on this is going to be Bulletproof TLS, which has a chapter about JSSE and Tomcat. 最好的参考将是Bulletproof TLS,其中有一章是关于JSSE和Tomcat的。
Is there a way to see what keystore if any is being used by a servlet, and what its location happens to be?
有没有办法查看servlet正在使用什么密钥库,以及它的位置是什么?
This depends on an SSLEngine being set up -- if you're running inside a servlet, most likely the app server has already set up your SSL configuration already. 这取决于是否设置了SSLEngine-如果您正在Servlet中运行,则很可能是应用服务器已经设置了SSL配置。 However, you can debug your JVM by turning on
-Djavax.net.debug=ALL
, but it doesn't tell you what location on the filesystem the certificate came from unless you coded a custom KeyStore and TrustManager (which is lame). 但是,可以通过打开
-Djavax.net.debug=ALL
来调试JVM,但是除非您编写了自定义的KeyStore和TrustManager((脚),否则它不会告诉您证书来自文件系统的哪个位置。 Here's the debug info though: 这是调试信息:
Alternatively, what is the proper way to make a new one and have it be used/initialized?
另外,制作一个新的并且被使用/初始化的正确方法是什么?
This depends on your application server. 这取决于您的应用程序服务器。 If you just need to provide a custom SSLEngine, you can do something like this (from https://github.com/wsargent/activator-play-tls-example/blob/master/app/https/CustomSSLEngineProvider.scala ):
如果只需要提供自定义SSLEngine,则可以执行以下操作(来自https://github.com/wsargent/activator-play-tls-example/blob/master/app/https/CustomSSLEngineProvider.scala ):
class CustomSSLEngineProvider(appProvider: ApplicationProvider) extends SSLEngineProvider {
def readPassword(): Array[Char] = {
val passwordPath = FileSystems.getDefault.getPath("certs", "password")
Files.readAllLines(passwordPath).get(0).toCharArray
}
def readKeyInputStream(): java.io.InputStream = {
val keyPath = FileSystems.getDefault.getPath("certs", "example.com.jks")
Files.newInputStream(keyPath)
}
def readTrustInputStream(): java.io.InputStream = {
val keyPath = FileSystems.getDefault.getPath("certs", "clientca.jks")
Files.newInputStream(keyPath)
}
def readKeyManagers(): Array[KeyManager] = {
val password = readPassword()
val keyInputStream = readKeyInputStream()
try {
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType)
keyStore.load(keyInputStream, password)
val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
kmf.init(keyStore, password)
kmf.getKeyManagers
} finally {
keyInputStream.close()
}
}
def readTrustManagers(): Array[TrustManager] = {
val password = readPassword()
val trustInputStream = readTrustInputStream()
try {
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType)
keyStore.load(trustInputStream, password)
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
tmf.init(keyStore)
tmf.getTrustManagers
} finally {
trustInputStream.close()
}
}
def createSSLContext(applicationProvider: ApplicationProvider): SSLContext = {
val keyManagers = readKeyManagers()
val trustManagers = readTrustManagers()
// Configure the SSL context to use TLS
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(keyManagers, trustManagers, null)
sslContext
}
override def createSSLEngine(): SSLEngine = {
val sslContext = createSSLContext(appProvider)
// Start off with a clone of the default SSL parameters...
val sslParameters = sslContext.getDefaultSSLParameters
// Tells the server to ignore client's cipher suite preference.
// http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#cipher_suite_preference
sslParameters.setUseCipherSuitesOrder(true)
// http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SSLParameters
val needClientAuth = java.lang.System.getProperty("play.ssl.needClientAuth")
sslParameters.setNeedClientAuth(java.lang.Boolean.parseBoolean(needClientAuth))
// Clone and modify the default SSL parameters.
val engine = sslContext.createSSLEngine
engine.setSSLParameters(sslParameters)
engine
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.