Nik*_*bak 198 java ssl https keytool
它看起来像一个标准问题,但我无法在任何地方找到明确的方向.
我有java代码尝试连接到可能具有自签名(或过期)证书的服务器.代码报告以下错误:
[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught
when processing request: sun.security.validator.ValidatorException: PKIX path
building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
Run Code Online (Sandbox Code Playgroud)
据我了解,我必须使用keytool并告诉java允许这种连接是可以的.
解决此问题的所有说明都假设我完全熟练使用keytool,例如
为服务器生成私钥并将其导入密钥库
有没有人可以发布详细说明?
我正在运行unix,所以bash脚本最好.
不确定它是否重要,但代码是在jboss中执行的.
Pas*_*ent 293
这里基本上有两个选项:将自签名证书添加到JVM信任库或将客户端配置为
从浏览器导出证书并将其导入JVM信任库(以建立信任链):
<JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit
Run Code Online (Sandbox Code Playgroud)
禁用证书验证:
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
}
// Now you can access an https URL without having the certificate in the truststore
try {
URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}
Run Code Online (Sandbox Code Playgroud)
请注意,我根本不推荐选项#2.禁用信任管理器会使SSL的某些部分失效,并使您在中间攻击中容易受到攻击.首选选项#1,或者更好的是,让服务器使用由知名CA签名的"真实"证书.
Joh*_*all 20
有对信任的所有证书一个更好的选择:创建一个TrustStore能特异性信任一个给定的证书,并使用它来创建一个SSLContext从中获得SSLSocketFactory到集上HttpsURLConnection。这是完整的代码:
File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));
// Or if the crt-file is packaged into a jar file:
// CertificateFactory.getInstance("X.509").generateCertificate(this.class.getClassLoader().getResourceAsStream("server.crt"));
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
Run Code Online (Sandbox Code Playgroud)
您也可以KeyStore直接从文件加载或从任何受信任的来源检索 X.509 证书。
请注意,使用此代码,cacerts将不会使用中的证书。这个特定的HttpsURLConnection只会信任这个特定的证书。
我将此问题追溯到不属于默认JVM可信主机的证书提供程序JDK 8u74.提供商是www.identrust.com,但这不是我试图连接的域名.该域名已从该提供商处获得其证书.请参阅JDK/JRE中默认列表的交叉根覆盖信任? - 读下几个条目.另请参阅哪些浏览器和操作系统支持Let's Encrypt.
因此,为了连接到我感兴趣的域,其中有identrust.com我发出的证书,我执行了以下步骤.基本上,我必须得到jVM DST Root CA X3信任的identrust.com()证书.我能够使用Apache HttpComponents 4.5这样做:
1:在证书链下载说明中获取不受信任的证书.单击DST根CA X3链接.
2:将字符串保存到名为"DST Root CA X3.pem"的文件中.务必在文件的开头和结尾添加"----- BEGIN CERTIFICATE -----"和"----- END CERTIFICATE -----"行.
3:使用以下命令创建一个java密钥库文件cacerts.jks:
keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword
Run Code Online (Sandbox Code Playgroud)
4:将生成的cacerts.jks密钥库复制到java /(maven)应用程序的resources目录中.
5:使用以下代码加载此文件并将其附加到Apache 4.5 HttpClient.这将解决所有具有从indetrust.comutil oracle 发布的证书的域的问题,该证书将证书包含在JRE默认密钥库中.
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
new TrustSelfSignedStrategy())
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
Run Code Online (Sandbox Code Playgroud)
当项目构建时,cacerts.jks将被复制到类路径中并从那里加载.在这个时间点,我没有测试其他ssl网站,但如果上面的代码"链"在这个证书中,那么它们也会起作用,但是我不知道.
参考:自定义SSL上下文以及如何使用Java HttpsURLConnection接受自签名证书?
小智 8
Apache HttpClient 4.5支持接受自签名证书:
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(new TrustSelfSignedStrategy())
.build();
SSLConnectionSocketFactory socketFactory =
new SSLConnectionSocketFactory(sslContext);
Registry<ConnectionSocketFactory> reg =
RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", socketFactory)
.build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse sslResponse = httpClient.execute(httpGet);
Run Code Online (Sandbox Code Playgroud)
这将构建一个SSL套接字工厂,它将使用TrustSelfSignedStrategy它,将其注册到自定义连接管理器,然后使用该连接管理器执行HTTP GET.
我同意那些吟唱"不要在生产中这样做"的人,但是有一些用例可以接受生产之外的自签证书; 我们在自动化集成测试中使用它们,这样即使不在生产硬件上运行,我们也会使用SSL(就像在生产中一样).
小智 6
而不是设置默认套接字工厂(IMO 是一件坏事) - yhis 只会影响当前连接而不是您尝试打开的每个 SSL 连接:
URLConnection connection = url.openConnection();
// JMD - this is a better way to do it that doesn't override the default SSL factory.
if (connection instanceof HttpsURLConnection)
{
HttpsURLConnection conHttps = (HttpsURLConnection) connection;
// Set up a Trust all manager
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
{
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
{
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
{
}
} };
// Get a new SSL context
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
// Set our connection to use this SSL context, with the "Trust all" manager in place.
conHttps.setSSLSocketFactory(sc.getSocketFactory());
// Also force it to trust all hosts
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// and set the hostname verifier.
conHttps.setHostnameVerifier(allHostsValid);
}
InputStream stream = connection.getInputStream();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
287060 次 |
| 最近记录: |