javax.net.ssl.SSLHandshakeException:java.security.cert.CertPathValidatorException:找不到证书路径的信任锚

bir*_*rdy 26 java ssl android retrofit

我正在使用Retrofit来访问我的REST API.但是,当我把我的API放在ssl后面并访问它时,http://myhost/myapi我得到了这个错误:

我的API落后于SSL,我是否需要做一些额外的事情?

这是我如何连接:

private final String API = "https://myhost/myapi";

private final RestAdapter REST_ADAPTER = new RestAdapter.Builder()
        .setServer(API)
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .build();

01-10 09:49:55.621    2076-2100/com.myapp.mobile D/Retrofit? javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:401)
            at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
            at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
            at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
            at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
            at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:90)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:48)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:287)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:222)
            at $Proxy12.signin(Native Method)
            at com.myapp.loginactivity$3.doInBackground(LoginActivity.java:143)
            at com.myapp.loginactivity$3.doInBackground(LoginActivity.java:136)
            at android.os.AsyncTask$2.call(AsyncTask.java:287)
            at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at java.lang.Thread.run(Thread.java:841)
     Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
            at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:282)
            at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:202)
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:595)
            at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:398)
            at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
            at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
            at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
            at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
            at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:90)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:48)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:287)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:222)
            at $Proxy12.signin(Native Method)
            at com.myapp.LoginActivity$3.doInBackground(LoginActivity.java:143)
            at com.myapp.LoginActivity$3.doInBackground(LoginActivity.java:136)
            at android.os.AsyncTask$2.call(AsyncTask.java:287)
            at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at java.lang.Thread.run(Thread.java:841)
Run Code Online (Sandbox Code Playgroud)

Fer*_*o. 12

发生这种情况的原因是JVM/Dalvik对系统或用户证书存储中的CA证书没有信心.

要使用Retrofit修复此问题,如果使用okhttp,则使用其他客户端非常相似.
你要这样做:

一个).创建包含CA的公钥的证书库.为此,您需要为*nix启动下一个脚本.您需要在您的计算机上安装openssl,并从https://www.bouncycastle.org/ jar bcprov-jdk16-1.46.jar下载.下载此版本不是其他版本,1.5x版本与android 4.0.4不兼容.

#!/bin/bash

if [ -z $1 ]; then
  echo "Usage: cert2Android<CA cert PEM file>"
  exit 1
fi

CACERT=$1
BCJAR=bcprov-jdk16-1.46.jar

TRUSTSTORE=mytruststore.bks
ALIAS=`openssl x509 -inform PEM -subject_hash -noout -in $CACERT`

if [ -f $TRUSTSTORE ]; then
    rm $TRUSTSTORE || exit 1
fi

echo "Adding certificate to $TRUSTSTORE..."
keytool -import -v -trustcacerts -alias $ALIAS \
      -file $CACERT \
      -keystore $TRUSTSTORE -storetype BKS \
      -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
      -providerpath $BCJAR \
      -storepass secret

echo "" 
echo "Added '$CACERT' with alias '$ALIAS' to $TRUSTSTORE..."
Run Code Online (Sandbox Code Playgroud)

B).将文件truststore mytruststore.bks复制到项目的res/raw中 信任库位置

C).设置连接的SSLContext:

.............
okHttpClient = new OkHttpClient();
try {
    KeyStore ksTrust = KeyStore.getInstance("BKS");
    InputStream instream = context.getResources().openRawResource(R.raw.mytruststore);
    ksTrust.load(instream, "secret".toCharArray());

    // TrustManager decides which certificate authorities to use.
    TrustManagerFactory tmf = TrustManagerFactory
        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(ksTrust);
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);

    okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) {
    e.printStackTrace();
}
.................
Run Code Online (Sandbox Code Playgroud)


Def*_*era 6

发生这种情况的原因有多种,包括:

  1. 颁发服务器证书的 CA 未知
  2. 服务器证书不是由 CA 签名的,而是自签名的
  3. 服务器配置缺少中间 CA

请查看此链接以获取解决方案: https://developer.android.com/training/articles/security-ssl.html#CommonProblems


tar*_*pra 6

基本上有四种潜在的解决方案来修复 Android 上的“javax.net.ssl.SSLHandshakeException:”异常

  1. 信任所有证书。不要这样做,除非你真的知道自己在做什么。
  2. 创建仅信任您的证书的自定义 SSLSocketFactory。只要您确切知道要连接到哪些服务器,这种方法就有效,但是一旦您需要使用不同的 SSL 证书连接到新服务器,您就需要更新您的应用程序。
  3. 创建一个包含 Android 证书“主列表”的密钥库文件,然后添加您自己的证书。如果这些证书中有任何一个过期,您有责任在您的应​​用程序中更新它们。我想不出这样做的理由。
  4. 创建一个使用内置证书 KeyStore 的自定义 SSLSocketFactory,但对于无法验证默认值的任何内容,则使用备用 KeyStore。点击此处对此进行了很好的解释

另外,我想详细说明第 1 点。我们可以使用清单网络配置有选择地跳过某些域,如下所示:

  1. 在 res 文件夹的 xml 文件夹中创建文件“network_security_config.xml”,其中包含以下内容。

       <network-security-config xmlns:tools="http://schemas.android.com/tools"
         xmlns:android="http://schemas.android.com/apk/res/android">
             <domain-config>
              <domain includeSubdomains="true">191.1.1.0</domain>
              <domain includeSubdomains="true">your_domain</domain>
             <trust-anchors>
                 <certificates src="system" />
                 <certificates src="user" />
             </trust-anchors>
         </domain-config>
     </network-security-config>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将“network_security_config.xml”添加到清单中的应用程序标记中,如下所示:

    android:networkSecurityConfig="@xml/network_security_config"

就这样..完成了!您已成功跳过 SSL 证书。

  • 在android 7.0中不工作 (4认同)

vij*_*jay 5

修复 Android N 及以上版本:我遇到了类似的问题,并按照https://developer.android.com/training/articles/security-config 中描述的步骤解决它

但配置的改变,没有任何复杂的代码逻辑,只适用于Android 24及以上版本。

修复所有版本,包括版本 < N: 因此对于 Android 低于 N(版本 24)的解决方案是通过如上所述的代码更改。如果您使用 OkHttp,则遵循 customTrust: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java


Kev*_*sox 1

SSL 未正确配置。这些 trustAnchor 错误通常意味着无法找到信任存储。检查您的配置并确保您确实指向信任存储并且它已就位。

确保您-Djavax.net.ssl.trustStore设置了系统属性,然后检查路径是否实际通向信任存储区。

您还可以通过设置此系统属性来启用 SSL 调试-Djavax.net.debug=all。在调试输出中,您会注意到它指出找不到信任存储区。