未找到Android SSL连接的信任锚

Chr*_*pix 156 ssl android ssl-certificate

我正在尝试连接到运行godaddy 256位SSL证书的IIS6盒子,我收到错误:

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
Run Code Online (Sandbox Code Playgroud)

一直试图确定可能导致这种情况的原因,但现在正在绘制空白.

这是我如何连接:

HttpsURLConnection conn;              
conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
conn.setConnectTimeout(20000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
String tempString = toString(conn.getInputStream()); 
Run Code Online (Sandbox Code Playgroud)

Ste*_*vie 203

相反,接受的答案,你并不需要一个定制信任管理器,你需要修复服务器配置!

我在连接到安装了错误的dynadot/alphassl证书的Apache服务器时遇到了同样的问题.我正在使用HttpsUrlConnection(Java/Android)连接,它正在投掷 -

javax.net.ssl.SSLHandshakeException: 
  java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.
Run Code Online (Sandbox Code Playgroud)

实际问题是服务器配置错误 - 使用http://www.digicert.com/help/或类似方法对其进行测试,它甚至会告诉您解决方案:

"证书未由受信任的机构签名(检查Mozilla的根存储区).如果您从受信任的机构购买证书,您可能只需安装一个或多个中级证书.请联系您的证书提供商以获取帮助服务器平台."

您还可以使用openssl检查证书:

openssl s_client -debug -connect www.thedomaintocheck.com:443

你可能会看到:

Verify return code: 21 (unable to verify the first certificate)

并且,在输出的早期:

depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=21:unable to verify the first certificate`
Run Code Online (Sandbox Code Playgroud)

证书链只包含1个元素(您的证书):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
  i:/O=AlphaSSL/CN=AlphaSSL CA - G2
Run Code Online (Sandbox Code Playgroud)

...但是应该将链中的签名机构引回到受Android(Verisign,GlobalSign等)信任的链中:

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
   i:/O=AlphaSSL/CN=AlphaSSL CA - G2
 1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
 2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
Run Code Online (Sandbox Code Playgroud)

用于配置服务器的说明(和中间证书)通常由颁发证书的机构提供,例如:http://www.alphassl.com/support/install-root-certificate.html

安装我的证书颁发者提供的中间证书后,我现在使用HttpsUrlConnection进行连接时没有错误.

  • 毫无疑问,您的解决方案是有效的,但是您不同意它是一种解决方法而不是根本原因的修复方法吗?如果我必须从3个客户端(Android,iOS,Windows Mobile)连接到服务器,那么我必须对所有3个应用解决方法,而我可以修复服务器一次,它们都将"正常工作". (8认同)
  • 如果OP可以访问他要连接的服务器SSL配置,则可能是一种解决方案。但是,如果他不是托管要连接的服务的人,则必须自己解决问题,这意味着要实现自定义信任管理器。 (3认同)
  • 感谢Stevie,我的服务器配置错误了3个月,直到现在我才检测到这一点!现在我的android应用正在运行100% (2认同)
  • @Stevie我对共享相同域的不同API进行了多次调用,但只有其中一个失败了(javax.net.ssl.SSLHandshakeException)...任何想法为什么会发生这种情况?顺便说一句,SSL证书不受信任.所以,我认为所有的调用都会失败并出现同样的异常. (2认同)

Mat*_*s B 71

@Chrispix的解决方案很危险!信任所有证书允许任何人在中间攻击中做一个人!只需将任何证书发送给客户端即可接受!

将您的证书添加到自定义信任管理器,如本文所述:使用HttpClient通过HTTPS信任所有证书

虽然使用自定义证书建立安全连接有点复杂,但它会为您带来所需的ssl加密安全性,而不会受到中间人攻击的危险!

  • @Chrispix,你不应该删除部分修复,它只是为了测试目的 (4认同)
  • @Stevie接受每个证书只是概念验证测试的一个选项,其中SSL连接不是您要测试的部分.否则,如果您接受每个证书,则不必使用SSL,因为连接不安全! (3认同)
  • 提个醒。我删除了我粘贴的“解决方案”作为变通方法,以免引起更多问题,因为人们并不认为它是“临时变通方法”。 (2认同)

kli*_*mat 16

您可以在运行时信任特定证书.
只需从服务器下载它,放入资源并使用ssl-utils-android加载:

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
Run Code Online (Sandbox Code Playgroud)

在我上面使用的示例中,OkHttpClientSSLContext可以与Java中的任何客户端一起使用.

如果您有任何问题随时问.我是这个小型图书馆的作者.

  • 这不是不安全吗,因为任何用户一旦拥有 apk 就可以访问应用程序的资产文件夹? (4认同)
  • @PatriceAndala,根 CA 是公开可用的,所以没问题 (4认同)

use*_*104 12

根据最新的Android文档更新(2017年3月):

当您遇到此类错误时:

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:374)
        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.getInputStream(HttpURLConnectionImpl.java:177)
        at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
Run Code Online (Sandbox Code Playgroud)

问题可能是以下之一:

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

解决方案是教导HttpsURLConnection信任一组特定的CA. 怎么样?请查看https://developer.android.com/training/articles/security-ssl.html#CommonProblems

谁正在使用其他AsyncHTTPClientcom.loopj.android:android-async-http库,请检查设置AsyncHttpClient使用HTTPS.

  • 如果一个人使用okhttp客户端呢? (4认同)

HA *_*A S 9

回复很老的帖子.但也许它会帮助一些新手,如果没有上述工作.

说明:我知道没有人想解释废话; 而是解决方案.但在一个班轮中,您尝试从本地计算机访问服务到不信任您的计算机的远程计算机.您请求需要从远程服务器获得信任.

解决方案:以下解决方案假定您满足以下条件

  1. 尝试从本地计算机访问远程api.
  2. 您正在为Android应用构建
  3. 您的远程服务器处于代理过滤状态(您在浏览器设置中使用代理来访问远程api服务,通常是登台或开发服务器)
  4. 您正在测试真实设备

脚步:

您需要一个.keystore扩展名文件来注册您的应用.如果你不知道如何创建.keystore文件; 然后按照以下部分创建.keystore文件或以其他方式跳到下一节Sign Apk File

创建.keystore文件

打开Android Studio.单击顶部菜单构建>生成签名APK.在下一个窗口中,单击" 创建新..."按钮.在新窗口中,请输入所有字段的数据.请记住,我推荐的两个密码字段应该具有相同的密码; 不要使用不同的密码; 并且还记住最顶层字段密钥存储路径的保存路径:.输入所有字段后,单击"确定"按钮.

签署Apk文件

现在,您需要使用刚创建的.keystore文件构建已签名的应用程序.跟着这些步骤

  1. 建立>清洁项目,等到它完成清洁
  2. 构建>生成签名APK
  3. 点击Choose existing...按钮
  4. 选择我们刚刚在Create .keystore文件部分中创建的.keystore文件
  5. 输入在Create .keystore文件部分中创建时创建的相同密码.使用相同的密码Key store passwordKey password字段.也输入别名
  6. 单击下一步按钮
  7. 在下一个屏幕中; 根据您在build.gradle文件中的设置可能会有所不同,您需要选择Build TypesFlavors.
  8. 对于Build Types选择release从下拉菜单中
  9. 对于Flavors然而,将取决于在你的设置build.gradle文件.staging从这个字段中选择.我使用了以下设置build.gradle,您可以使用与我相同的设置,但请确保更改applicationId为您的包名称

    productFlavors {
        staging {
            applicationId "com.yourapplication.package"
            manifestPlaceholders = [icon: "@drawable/ic_launcher"]
            buildConfigField "boolean", "CATALYST_DEBUG", "true"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "true"
        }
        production {
            buildConfigField "boolean", "CATALYST_DEBUG", "false"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "false"
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  10. 单击底部的两个Signature Versions复选框,然后单击Finish按钮.

差不多了:

所有的辛勤工作都已完成,现在是真理的运动.要访问由代理备份的Staging服务器,您需要在真正的Android设备测试中进行一些设置.

Android设备中的代理设置:

  1. 单击Android手机内的设置,然后单击Wi-Fi
  2. 长按连接的wifi并选择 Modify network
  3. Advanced options如果您看不到该Proxy Hostname字段,请单击
  4. Proxy Hostname输入要连接的主机IP或名称.典型的临时服务器将命名为stg.api.mygoodcompany.com
  5. 例如,对于端口,输入四位数的端口号 9502
  6. 按下Save按钮

最后一站:

请记住,我们在Sign APK文件部分生成了已签名的apk文件.现在是安装该APK文件的时候了.

  1. 打开终端并更改为已签名的apk文件夹
  2. 将Android设备连接到您的计算机
  3. 从Android设备中删除以前安装的所有apk文件
  4. adb install name of the apk file
  5. 如果由于某种原因上面的命令返回adb command not found.输入完整路径C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe install name of the apk file

我希望问题可以解决.如果没有,请给我留言.

萨拉姆!


avi*_*ney 9

我在尝试使用使用自签名证书来公开其测试版本的外部 Web 服务时遇到了同样的问题。以下是我用于全局解决该问题的步骤(它将应用您使用的任何框架:Retrofit、oKhttp、HttpUrlConnection)

  1. 在 chrome 中加载域 ( https://dev.thedomain.private )
  2. 以 .der 格式导出证书(padlock symbol在 url 附近,然后details选择export格式der
  3. 将 der 保存到原始文件夹中res/raw/dev_thedomain_private.der
  4. 在下面创建一个安全配置文件resources/xml
    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <domain-config>
            <domain includeSubdomains="true">dev.thedomain.private</domain>
            <trust-anchors>
                <certificates src="@raw/dev_thedomain_private"/>
            </trust-anchors>
        </domain-config>
    </network-security-config>
Run Code Online (Sandbox Code Playgroud)
  1. 在应用程序标签下引用清单中的安全配置
    <application
        android:networkSecurityConfig="@xml/network_security_config"
Run Code Online (Sandbox Code Playgroud)

你完成了 !该证书现在将被信任...


Shi*_*din 7

如果使用改造,则需要自定义OkHttpClient。

retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
Run Code Online (Sandbox Code Playgroud)

完整代码如下。

    public class RestAdapter {

    private static Retrofit retrofit = null;
    private static ApiInterface apiInterface;

    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // 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.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            return builder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static ApiInterface getApiClient() {
        if (apiInterface == null) {

            try {
                retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

            } catch (Exception e) {

                e.printStackTrace();
            }


            apiInterface = retrofit.create(ApiInterface.class);
        }
        return apiInterface;
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 这是根本不安全的。不使用。 (6认同)

Coo*_*ind 6

使用https://www.ssllabs.com/ssltest/测试域。

Shihab Uddin在 Kotlin 中的解决方案。

import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.security.cert.CertificateException

object {

    val okHttpClient: OkHttpClient
    val gson: Gson
    val retrofit: Retrofit

    init {

        okHttpClient = getOkHttpBuilder()
            // Other parameters like connectTimeout(15, TimeUnit.SECONDS)
            .build()

        gson = GsonBuilder().setLenient().create()

        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
    }

    fun getOkHttpBuilder(): OkHttpClient.Builder =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            OkHttpClient().newBuilder()
        } else {
            // Workaround for the error "Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate expired at".
            getUnsafeOkHttpClient()
        }

    private fun getUnsafeOkHttpClient(): OkHttpClient.Builder =
        try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts: Array<TrustManager> = arrayOf(
                object : X509TrustManager {
                    @Throws(CertificateException::class)
                    override fun checkClientTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
                }
            )
            // Install the all-trusting trust manager
            val sslContext: SSLContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())
            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory,
                trustAllCerts[0] as X509TrustManager)
            builder.hostnameVerifier { _, _ -> true }
            builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
}
Run Code Online (Sandbox Code Playgroud)

如果使用Glide,也会出现同样的错误,图像不会显示。要克服它,请参阅Glide - javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for Certification path not foundHow to set OkHttpClient for glide

@GlideModule
class MyAppGlideModule : AppGlideModule() {

    val okHttpClient = Api.getOkHttpBuilder().build() // Api is the class written above.
    // It is better to create okHttpClient here and not use Api.okHttpClient,
    // because their settings may differ. For instance, it can use its own
    // `addInterceptor` and `addNetworkInterceptor` that can affect on a read JSON.


    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        registry.replace(GlideUrl::class.java, InputStream::class.java,
            OkHttpUrlLoader.Factory(okHttpClient))
    }
}
Run Code Online (Sandbox Code Playgroud)

构建.gradle:

// Glide.
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
Run Code Online (Sandbox Code Playgroud)

更新

我还在 API 16 模拟器上遇到了另一个错误:

例程:SSL23_GET_SERVER_HELLO:tlsv1 警报协议版本 (external/openssl/ssl/s23_clnt.c:741'.

阅读12,我更改了代码:

okHttpClient = getOkHttpBuilder().build()

private fun getOkHttpBuilder(): OkHttpClient.Builder {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        Security.insertProviderAt(Conscrypt.newProvider(), 1)
    }
    return OkHttpClient().newBuilder()
}

// build.gradle:
implementation 'org.conscrypt:conscrypt-android:2.5.1'
Run Code Online (Sandbox Code Playgroud)

我还从以下内容中删除了这些行MyApplication

try {
    ProviderInstaller.installIfNeeded(applicationContext)
    val sslContext = SSLContext.getInstance("TLSv1.2")
    sslContext.init(null, null, null)
    sslContext.createSSLEngine()
} catch (e: GooglePlayServicesRepairableException) {
    Timber.e(e.stackTraceToString())
    // Prompt the user to install/update/enable Google Play services.
    GoogleApiAvailability.getInstance().showErrorNotification(this, e.connectionStatusCode)
} catch (e: GooglePlayServicesNotAvailableException) {
    Timber.e(e.stackTraceToString())
    // Prompt the user to install/update/enable Google Play services.
    // GoogleApiAvailability.getInstance().showErrorNotification(this, e.errorCode)
} catch (e: NoSuchAlgorithmException) {
    Timber.e(e.stackTraceToString())
} catch (e: KeyManagementException) {
    Timber.e(e.stackTraceToString())
}
Run Code Online (Sandbox Code Playgroud)

但是该为 apk 增加了 3.4 Mb。


Sah*_*iya 5

我遇到了同样的问题,我发现我提供的证书 .crt 文件缺少中间证书。因此,我向服务器管理员询问了所有 .crt 文件,然后以相反的顺序将它们连接起来。

前任。1.Root.crt 2.Inter.crt 3.myCrt.crt

在Windows中我执行了copy Inter.crt + Root.crt newCertificate.crt

(这里我忽略了myCrt.crt)

然后我通过输入流将 newCertificate.crt 文件提供到代码中。完工。


Adr*_* C. 5

我知道您不需要信任所有证书,但就我而言,我在一些调试环境中遇到了问题,在这些环境中我们有自签名证书,我需要一个肮脏的解决方案。

我所要做的就是更改sslContext

mySSLContext.init(null, trustAllCerts, null); 
Run Code Online (Sandbox Code Playgroud)

在哪里trustAllCerts创建是这样的:

private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[]{};
    }

    public void checkClientTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }
} };
Run Code Online (Sandbox Code Playgroud)

希望这会派上用场。

  • 这是根本不安全的。不使用。 (7认同)

归档时间:

查看次数:

325530 次

最近记录:

6 年,8 月 前