为了账号安全,请及时绑定邮箱和手机立即绑定

接受具有自签名证书的HTTPS连接

接受具有自签名证书的HTTPS连接

慕森卡 2019-06-24 14:56:17
接受具有自签名证书的HTTPS连接我试图建立HTTPS连接,使用HttpClient但是问题是,由于证书不是由一个公认的证书颁发机构(CA)签署的,维瑞,环球信等等,在android可信证书集上,我一直得到javax.net.ssl.SSLException: Not trusted server certificate.我已经看到了简单地接受所有证书的解决方案,但是如果我想问用户呢?我想要一个类似浏览器的对话框,让用户决定是否继续。最好我想使用与浏览器相同的证书。有什么想法吗?
查看完整描述

3 回答

?
红糖糍粑

TA贡献1815条经验 获得超6个赞

如果服务器上的设备上没有自定义/自签名证书,则可以使用下面的类加载它,并在Android的客户端使用它:

放置证书*.crt文件在/res/raw使其可从R.raw.*

使用下面的类获取HTTPClientHttpsURLConnection它将有一个套接字工厂使用该证书:

package com.example.customssl;import android.content.Context;import org.apache.http.client.HttpClient;import org.apache.http.conn.scheme.
PlainSocketFactory;import org.apache.http.conn.scheme.Scheme;import org.apache.http.conn.scheme.SchemeRegistry;import org.apache.http.conn
.ssl.AllowAllHostnameVerifier;import org.apache.http.conn.ssl.SSLSocketFactory;import org.apache.http.impl.client.DefaultHttpClient;import 
org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;import org.apache.http.params.BasicHttpParams;import org.apache.http.params.Ht
tpParams;import javax.net.ssl.HttpsURLConnection;import javax.net.ssl.SSLContext;import javax.net.ssl.TrustManagerFactory;import java.io.IO
Exception;import java.io.InputStream;import java.net.URL;import java.security.KeyStore;import java.security.KeyStoreException;import java.s
ecurity.NoSuchAlgorithmException;import java.security.cert.Certificate;import java.security.cert.CertificateException;import java.security.
cert.CertificateFactory;public class CustomCAHttpsProvider {

    /**
     * Creates a {@link org.apache.http.client.HttpClient} which is configured to work with a custom authority
     * certificate.
     *
     * @param context       Application Context
     * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
     * @param allowAllHosts If true then client will not check server against host names of certificate.
     * @return Http Client.
     * @throws Exception If there is an error initializing the client.
     */
    public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {


        // build key store with ca certificate
        KeyStore keyStore = buildKeyStore(context, certRawResId);

        // init ssl socket factory with key store
        SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);

        // skip hostname security check if specified
        if (allowAllHosts) {
            sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
        }

        // basic http params for client
        HttpParams params = new BasicHttpParams();

        // normal scheme registry with our ssl socket factory for "https"
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));

        // create connection manager
        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);

        // create http client
        return new DefaultHttpClient(cm, params);
    }

    /**
     * Creates a {@link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
     * certificate.
     *
     * @param urlString     remote url string.
     * @param context       Application Context
     * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
     * @param allowAllHosts If true then client will not check server against host names of certificate.
     * @return Http url connection.
     * @throws Exception If there is an error initializing the connection.
     */
    public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
                                                           boolean allowAllHosts) throws Exception {

        // build key store with ca certificate
        KeyStore keyStore = buildKeyStore(context, certRawResId);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        // Create a connection from url
        URL url = new URL(urlString);
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

        // skip hostname security check if specified
        if (allowAllHosts) {
            urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
        }

        return urlConnection;
    }

    private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException,
     NoSuchAlgorithmException, IOException {
        // init a default key store
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);

        // read and add certificate authority
        Certificate cert = readCert(context, certRawResId);
        keyStore.setCertificateEntry("ca", cert);

        return keyStore;
    }

    private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {

        // read certificate resource
        InputStream caInput = context.getResources().openRawResource(certResourceId);

        Certificate ca;
        try {
            // generate a certificate
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            ca = cf.generateCertificate(caInput);
        } finally {
            caInput.close();
        }

        return ca;
    }}

要点:

  1. Certificate

    对象是从

    .crt

    档案。
  2. 违约

    KeyStore

    是被创造出来的。
  3. keyStore.setCertificateEntry("ca", cert)

    将证书添加到别名“ca”下的密钥存储区。您可以修改代码以添加更多证书(中间CA等)。
  4. 主要目标是生成一个

    SSLSocketFactory

    然后可以由

    HTTPClient

    HttpsURLConnection.

  5. SSLSocketFactory

    可以进一步配置,例如跳过主机名验证等。

详情见:http:/developer.android.com/培训/文章/安全-ssl.html


查看完整回答
反对 回复 2019-06-24
  • 3 回答
  • 0 关注
  • 397 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信