ssl 异常错误:主机名domain.com未验证

ykejflvf  于 2022-11-14  发布在  其他
关注(0)|答案(7)|浏览(283)

我已经试了好几天了。我试着用一个自签名证书通过https连接到我的服务器。我想现在已经没有我没有读过的页面或示例了。
我所做的:
1.按照以下教程创建了bks密钥库:http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
它使用openssl s_client -connect domain.com:443从服务器获取证书,然后使用bouncy castle创建一个bks密钥库。
1.从原始文件夹阅读已创建的密钥库,将其添加到sslfactory,然后添加到OkHttpClient。如下所示:

public ApiService() {
    mClient = new OkHttpClient();
    mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
    mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
    mClient.setCache(getCache());
    mClient.setCertificatePinner(getPinnedCerts());
    mClient.setSslSocketFactory(getSSL());
}

protected SSLSocketFactory getSSL() {
    try {
        KeyStore trusted = KeyStore.getInstance("BKS");
        InputStream in = Beadict.getAppContext().getResources().openRawResource(R.raw.mytruststore);
        trusted.load(in, "pwd".toCharArray());
        SSLContext sslContext = SSLContext.getInstance("TLS");
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trusted);
        sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
        return sslContext.getSocketFactory();
    } catch(Exception e) {
        e.printStackTrace();
    }
    return null;
}

public CertificatePinner getPinnedCerts() {
    return new CertificatePinner.Builder()
            .add("domain.com", "sha1/theSha=")
            .build();
}

1.由于某种原因,这总是生成一个SSLPeerUnverifiedException,有或没有密钥库,有或没有CertificatePinner .

javax.net.ssl.SSLPeerUnverifiedException: Hostname domain.com not verified: 0         
 W/System.err﹕ certificate: sha1/theSha=
 W/System.err﹕ DN: 1.2.840.113549.1.9.1=#1610696e666f40626561646963742e636f6d,CN=http://domain.com,OU=development,O=domain,L=Valencia,ST=Valencia,C=ES
 W/System.err﹕ subjectAltNames: []
 W/System.err﹕ at com.squareup.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:124)
 W/System.err﹕ at com.squareup.okhttp.Connection.connect(Connection.java:143)
 W/System.err﹕ at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185)
 W/System.err﹕ at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
 W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
 W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
 W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
 W/System.err﹕ at com.squareup.okhttp.Call.getResponse(Call.java:273)
 W/System.err﹕ at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:230)
 W/System.err﹕ at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:201)
 W/System.err﹕ at com.squareup.okhttp.Call.execute(Call.java:81)
 ...

我做错了什么?

ktecyv1j

ktecyv1j1#

我遇到了同样的问题,但是我需要我的应用程序在几个临时环境中工作,所有这些环境都有自签名的证书。
为了解决这个问题,当连接到staging only时,我添加了一个信任所有证书的SSLSocketFactory。这修复了java错误,但是它给我留下了这个票证中提到的okhttp异常。
为了避免这个错误,我需要再添加一个自定义到我的okHttpClient。这为我修复了这个错误。

okHttpClient.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
rkttyhzu

rkttyhzu2#

我终于得到了这个工作与混合多个答案。
首先,证书是错误的,不知道是怎么做的。但是通过使用this answer中的脚本来创建它们,它们就可以工作了。需要的是一个服务器证书和一个密钥。然后客户端需要另一个证书。
为了在android中使用证书,我将.pem文件转换为.crt文件,如下所示:

openssl x509 -outform der -in client.pem  -out client.crt

在android中,我将证书添加到我的OkHttp客户端,如下所示:

public ApiService() {
    mClient = new OkHttpClient();
    mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
    mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
    mClient.setCache(getCache());
    mClient.setSslSocketFactory(getSSL());
}

protected SSLSocketFactory getSSL() {
    try {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream cert = getAppContext().getResources().openRawResource(R.raw.client);
        Certificate ca = cf.generateCertificate(cert);
        cert.close();

        // creating a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        return new AdditionalKeyStore(keyStore);
    } catch(Exception e) {
        e.printStackTrace();
    }
    return null;
}

new AdditionalKeyStore()的最后一部分取自this very well written answer,它添加了一个后备密钥库。
我希望这对其他人有帮助!这是我找到的让HTTPS使用自签名证书的最简单的方法。其他方法包括拥有一个BouncyCastle密钥库,这对我来说似乎太过分了。

6za6bjd0

6za6bjd03#

通过将setHostNameVerifier设置为okHttpBuilder可解决此问题。请确保verify方法应返回true。
样品:

okHttpClient.setHostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
});

OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.hostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    });
OkHttpClient client = builder.build();
nmpmafwu

nmpmafwu4#

请检查客户端证书上的CN名称是否已添加到主题替代名称中。我遇到了同样的问题

2wnc66cl

2wnc66cl5#

在凭证产生期间,如果uri是IP,则必须设定subjectAltName,才不会通过验证。
“在某些情况下,URI被指定为IP地址而不是主机名。在这种情况下,iPhress subjectAltName必须出现在证书中,并且必须与URI中的IP完全匹配。”RFC(Bas在注解中提到)
不要在客户端使用HostnameVerifier或其他方法,而是通过以下方式释放自签名证书(我们可以控制它):

openssl req \
-newkey rsa:2048 \
-nodes \
-x509 \
-days 36500 -nodes \
-addext "subjectAltName = IP.1:1.2.3.4" \
-keyout /etc/ssl/private/nginx-selfsigned2.key \
-out /etc/ssl/certs/nginx-selfsigned2.crt

如果在android上,还需要信任证书:

the crt is pem format and can be imported into android via
<?xml version="1.0" encoding="utf-8"?>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="@raw/nginx_selfsigned2" />
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

因此,我们验证证书来自受信任的源,并且以前通过主机名验证(通过SAN)确保我们与之交谈的服务器为他的IP提供正确的证书。
更多信息,请访问:https://developer.android.com/training/articles/security-config https://developer.android.com/training/articles/security-ssl.html#SelfSigned

vsaztqbk

vsaztqbk6#

如果你在res/xml中使用network_security_config来解决Cleartext HTTP traffic not permitted,并且你改变了域/IP地址,记住你应该把includeSubdomains的值改为新的地址。

<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
      <domain includeSubdomains="true">yourDomain.com</domain>
    </domain-config>
  </network-security-config>
ohfgkhjo

ohfgkhjo7#

使用HTTPS而不是HTTP也会导致此错误。
当您将URL更改为HTTP时,不要忘记在application标记内的AndroidManifest文件上添加android:usesCleartextTraffic="true"

相关问题