编辑:我试图在我的博客上以更得体的方式格式化问题和接受的答案。
这是最初的问题。
我得到这个错误:
详细消息sun.security.validator.ValidatorException: PKIX路径
构建失败:
provider.certpath. suncertpathbuilderexception:不能
找到请求目标的有效认证路径
导致javax.net.ssl.SSLHandshakeException:
validatorexception: PKIX路径构建
失败:sun.security.provider.certpath.SunCertPathBuilderException:
无法找到请求目标的有效认证路径
我使用Tomcat 6作为web服务器。我在同一台机器上的不同端口的不同Tomcats上安装了两个HTTPS web应用程序。假设App1(端口8443)和App2(端口443)。App1连接到App2。当App1连接到App2时,我得到上述错误。我知道这是一个非常常见的错误,所以在不同的论坛和网站上找到了许多解决方案。我在两个Tomcats的server.xml中有以下条目:
keystoreFile="c:/.keystore"
keystorePass="changeit"
每个站点都说明了app2给出的证书不在app1 jvm的可信存储区中的相同原因。这似乎也是真的,当我试图在IE浏览器中点击相同的URL,它工作(与升温,有一个问题与此网站的安全证书。在这里我说继续这个网站)。但是当相同的URL被Java客户端(在我的情况下)击中时,我得到上述错误。为了把它放到信任库中,我尝试了以下三个选项:
选项1
System.setProperty("javax.net.ssl.trustStore", "C:/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
选项2
在环境变量中设置如下
CATALINA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value
选项3
在环境变量中设置如下
JAVA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value
结果
但是什么都不管用。
最后工作是执行Java方法建议如何处理无效的SSL证书与Apache HttpClient?通过Pascal Thivent,即执行程序InstallCert。
但这种方法适用于开发盒设置,但我不能在生产环境中使用它。
我想知道为什么上面提到的三种方法都不工作,而我已经通过设置在App2服务器的server.xml中提到了相同的值,在truststore中也提到了相同的值
System.setProperty("javax.net.ssl.trustStore", "C:/.keystore")和System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
在App1程序中。
要了解更多信息,这是我如何建立联系:
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection conn1 = (HttpsURLConnection) url.openConnection();
conn1.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
reply.load(conn1.getInputStream());
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效认证路径
•当我得到错误时,我尝试谷歌表达式的含义,我发现,当服务器更改其HTTPS SSL证书时,会发生此问题,而我们的旧版本的java不识别根证书颁发机构(CA)。
•如果您可以在浏览器中访问HTTPS URL,则可以更新Java以识别根CA。
•在浏览器中,转到Java无法访问的HTTPS URL。单击HTTPS证书链(ie浏览器中有锁图标),单击锁即可查看证书。
•进入证书的“详细信息”和“复制到文件”。复制为Base64 (.cer)格式。它将保存在您的桌面上。
•安装证书时忽略所有警告。
•这就是我如何收集我试图访问的URL的证书信息。
现在我必须让我的java版本知道这个证书,这样它就不会拒绝识别URL了。在这方面,我必须提到,我搜索到根证书信息默认保存在JDK的\jre\lib\security位置,默认访问密码是:changeit。
查看cacerts信息的操作步骤如下:
•点击开始按钮——>运行
•输入cmd。打开命令提示符(您可能需要以管理员身份打开它)。
•进入Java/jreX/bin目录
•输入以下内容
keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts
它给出密钥存储库中包含的当前证书的列表。它看起来是这样的:
C:\Documents and Settings\NeelanjanaG>keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts
Enter keystore password: changeit
Keystore type: jks
Keystore provider: SUN
Your keystore contains 44 entries
verisignclass3g2ca, Mar 26, 2004, trustedCertEntry,
Certificate fingerprint (MD5): A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9
entrustclientca, Jan 9, 2003, trustedCertEntry,
Certificate fingerprint (MD5): 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4
thawtepersonalbasicca, Feb 13, 1999, trustedCertEntry,
Certificate fingerprint (MD5): E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41
addtrustclass1ca, May 1, 2006, trustedCertEntry,
Certificate fingerprint (MD5): 1E:42:95:02:33:92:6B:B9:5F:C0:7F:DA:D6:B2:4B:FC
verisignclass2g3ca, Mar 26, 2004, trustedCertEntry,
Certificate fingerprint (MD5): F8:BE:C4:63:22:C9:A8:46:74:8B:B8:1D:1E:4A:2B:F6
•现在我必须将之前安装的证书包含到cacerts中。
•为此,程序如下:
keytool -import -noprompt -trustcacerts -alias ALIASNAME -file FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass PASSWORD
如果你使用的是Java 7:
keytool -importcert -trustcacerts -alias ALIASNAME -file PATH_TO_FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass changeit
•然后将证书信息添加到cacert文件中。
这是我为上面提到的异常找到的解决方案!!
如何在Tomcat 7中工作
我想在Tomcat应用程序中支持自签名证书,但下面的代码片段无法工作
import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HTTPSPlayground {
public static void main(String[] args) throws Exception {
URL url = new URL("https:// ... .com");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
httpURLConnection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
String serializedMessage = "{}";
wr.writeBytes(serializedMessage);
wr.flush();
wr.close();
int responseCode = httpURLConnection.getResponseCode();
System.out.println(responseCode);
}
}
这就是解决我问题的方法:
1)下载。crt文件
echo -n | openssl s_client -connect <your domain>:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/<your domain>.crt
将<您的域名>替换为您的域名(例如jossef.com)
2)在Java的cacerts证书存储中应用.crt文件
keytool -import -v -trustcacerts -alias <your domain> -file ~/<your domain>.crt -keystore <JAVA HOME>/jre/lib/security/cacerts -keypass changeit -storepass changeit
将<您的域名>替换为您的域名(例如jossef.com)
将<JAVA HOME>替换为JAVA主目录
3)破解它
尽管iv在Java的默认证书存储中安装了我的证书,但Tomcat忽略了这一点(似乎它没有配置为使用Java的默认证书存储)。
要破解这个问题,在代码中添加以下代码:
String certificatesTrustStorePath = "<JAVA HOME>/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);
// ...
可以通过编程方式禁用SSL验证。对于开发人员来说非常有效,但不推荐用于生产环境,因为您可能需要在那里使用“真正的”SSL验证,或者安装并使用您自己的可信密钥,然后仍然使用“真正的”SSL验证。
下面的代码为我工作:
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class TrustAnyTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
HttpsURLConnection conn = null;
URL url = new URL(serviceUrl);
conn = (HttpsURLConnection) url.openConnection();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
conn.setHostnameVerifier(allHostsValid);
或者,如果您不控制下面的连接,您也可以为所有连接覆盖全局SSL验证https://stackoverflow.com/a/19542614/32453
如果你正在使用Apache HTTPClient,你必须“以不同的方式”禁用它:https://stackoverflow.com/a/2703233/32453
可部署解决方案(Alpine Linux)
为了能够在我们的应用程序环境中修复这个问题,我们准备了如下的Linux终端命令:
cd ~
将在主目录中生成证书文件。
apk add openssl
该命令在alpine Linux中安装openssl。您可以找到其他Linux发行版的适当命令。
openssl s_client -connect <host-dns-ssl-belongs> < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > public.crt
生成所需的证书文件。
sudo $JAVA_HOME/bin/keytool -import -alias server_name -keystore $JAVA_HOME/lib/security/cacerts -file public.crt -storepass changeit -noprompt
使用'keytool'程序将生成的文件应用到JRE。
注意:请将您的DNS替换为<host- DNS -ssl-belong >
注意:请注意-noprompt不会提示验证信息(yes/no), -storepass changeit参数将禁用密码提示并提供所需的密码(默认为'changeit')。这两个属性将允许您在应用程序环境中使用这些脚本,例如构建Docker映像。
注3:如果你是通过Docker部署你的应用程序,你可以生成一次秘密文件,并把它放在你的应用程序项目文件中。您不需要一次又一次地生成它。
我正在使用颤振,却突然收到这个错误。基本上发生的是,在android/build中依赖项中的行。Gradle文件,如:
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
要求从网上下载成绩文件的证明。但是当有什么东西阻止gradle下载这些证书时,通常会显示这个。
I tried exporting the certificate and adding it manually but it didn't seem to work for me. What worked for me, after countless head scratches, was disabling the proxies from your network preferences. It was somewhere mentioned that disabling Charles Proxy would fix it but at that moment, I was clueless what Charles was and what proxy was. And in my case, I did not have the Charles proxy thing so I went on with finding the proxies in the network preferences settings in Mac( it could be found somewhere in network settings for Windows). I had Socks enabled within the proxy. I disabled it and then again rebuilt the gradle and TA-DAH!!! It worked butter smooth.
There are a few things to remember. If you build your project right after disabling proxy without closing the network preferences tab, the disable proxies won't work and it will show the same error. Also if you've already built the project and you're running it again after disabling proxies, chances are it's gonna show the same error( could be due to IDE caches). How it worked for me: Restart the Mac, open a few tabs in the browser( for a few network calls), check the network preferences from system preferences>> wifi and disable proxies, close the system preferences app, and build the project.
对于OkHttpClient,这个解决方案适合我。
它可能会帮助使用图书馆的人……
try {
String proxyHost = "proxy_host";
String proxyUsername = "proxy_username";
String proxyPassword = "proxy_password";
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, "port goes here"));
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient client = new OkHttpClient().newBuilder()
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((hostname, session) -> true)
.connectTimeout(timeout, TimeUnit.SECONDS)
.proxy(proxy)
.proxyAuthenticator((route, response) -> {
String credential = Credentials.basic(proxyUsername, proxyPassword);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
})
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody requestBody = RequestBody.create(payload, mediaType);
Request request = new Request.Builder()
.url(url)
.header("Authorization", "authorization data goes here")
.method(requestMethod, requestBody)
.build();
Response response = client.newCall(request).execute();
resBody = response.body().string();
int responseCode = response.code();
} catch (Exception ex) {
}
我在Android Studio中得到这个错误。所以我做了很多研究之后。
“Password”为“changeit”
步骤1:以管理员身份打开CMD
第二步:输入Powershell
步骤3:start-process powershell -verb runas
步骤4:在C:\Program Files\Android\Android中添加所有的证书
Studio\jre\lib\security此位置是cacert可用的位置。
第五步:进入Keytool目录Set-Location -Path "C:\Program Files\Android\Android Studio\jre\bin"
第六步:在powershell中执行以下命令:\ keytool -importcert -trustcacerts -alias GiveNameforyourcertificate -file "C:\Program Files\Android\Android Studio\jre\lib\security\Replace With Your Certificate name. "Cer " -keystore cacerts
步骤7:如果错误出现为证书已添加(访问被拒绝),然后创建一个D驱动器分区(https://www.diskpart.com/windows-10/how-to-create-d-drive-from-c-drive-in-windows-10-0725.html)或移动您的文件到D驱动器,然后添加证书
如果你把文件保存在D盘,那么只执行这个
步骤8:keytool -importcert -trustcacerts -alias Nameyourcertificate -file "D:\Certificatename. txt "Cer " -keystore cacerts
\keytool -list -keystore cacerts . keystore cacerts . keystore - cacerts . keystore - cacerts . keystore - cacerts . keystore