Android中Https通信实现_ 单向认证

版权声明:本博客主要记录学习笔记和遇到的一些问题解决方案,转载请注明出处! https://blog.csdn.net/u010982507/article/details/85258477

客户端与服务端单向认证即是在客户端的网络请求和webview中设置信任所有证书,然后在与服务端进行Https网络通信的时候,客户端不必进行证书校验也能进行网络通信,否则就会报证书不受信异常。
缺陷:容易受到中间人攻击。

概览

  • TrustManager和HostnameVerifier
  • HttpURLConnection信任所有证书
  • OkHttp信任所有证书
  • webview信任所有证书

X509TrustManagerHostnameVerifier

X509TrustManager用于实现SSL证书的安全校验,若使用不当,将导致APP对SSL证书不作校验,从而 黑客有了中间人攻击的可乘之机。开发者常见错误:

  • 自定义X509TrustManager,且不做任何校验逻辑,一般为空实现;

HostnameVerifier用于实现HTTPS通信中的域名安全校验,即验证当前连接的HTTPS站点的SSL证书中的域名是否等于站点本身的域名。开发者常见错误:

  • 自定义HostnameVerifier,且不做任何校验逻辑,一般为return true;
  • 使用Android系统中自带的不安全的HostnameVerifier,效果等同于不做任何校验逻辑:
    org.apache.http.conn.ssl.AllowAllHostnameVerifier
    org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSLSocketClient {

    //获取这个SSLSocketFactory
    public static SSLSocketFactory getSSLSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, getTrustManager(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //获取TrustManager
    private static TrustManager[] getTrustManager() {
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                    		// return null; 或者
                        return new X509Certificate[]{}; // 空实现
                    }
                }
        };
        return trustAllCerts;
    }

    //获取HostnameVerifier
    public static HostnameVerifier getHostnameVerifier() {
        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
            	  // true表示信任所有域名
                return true;
            }
        };
        return hostnameVerifier;
    }
}

使用Android系统中自带的不安全的HostnameVerifie

URL url = new URL("https url");
HttpsURLConnection conn= (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

HttpURLConnection信任所有证书

URL url = new URL(fileUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(requestType);
conn.setConnectTimeout(timeOut * 1000);
// 配置https的证书
if ("https".equalsIgnoreCase(url.getProtocol())){
    ((HttpsURLConnection) conn).setSSLSocketFactory(SSLSocketClient.getSSLSocketFactory());
    ((HttpsURLConnection) conn).setHostnameVerifier(SSLSocketClient.getHostnameVerifier());
}

OkHttp信任所有证书

OkHttpClient okHttpClient = new OkHttpClient.Builder()
              .sslSocketFactory(SSLSocketClient.getSSLSocketFactory())
              .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
              .build();

webview信任所有证书

Android系统内置了一些可信机构办法的证书,可用于作HTTPS证书校验。实际上,使用Webview组件进HTTPS通信,其证书验证环节也是系统默认会去做的。若发现证书不合法,Webview将显示一个空白页面,其错误在onReceivedSslError()这个方法里进行处理。
在WebViewClient源码中可以看到系统默认处理,是拒绝连接带有可信机构颁发证书的HTTPS站点的,如下所示:

/**
  * Notify the host application that an SSL error occurred while loading a
  * resource. The host application must call either handler.cancel() or
  * handler.proceed(). Note that the decision may be retained for use in
  * response to future SSL errors. The default behavior is to cancel the
  * load.
  *
  * @param view The WebView that is initiating the callback.
  * @param handler An SslErrorHandler object that will handle the user's
  *            response.
  * @param error The SSL error object.
  */
 public void onReceivedSslError(WebView view, SslErrorHandler handler,
         SslError error) {
     // 拒绝连接
     handler.cancel();
 }

而我们重写此方法的时候可以设置成接受所有连接,如下所示:

 public void onReceivedSslError(WebView view, SslErrorHandler handler,
         SslError error) {
     // 接受所有连接
    handler.proceed();
 }

参考:
https://blog.csdn.net/jogger_ling/article/details/60576625
https://blog.csdn.net/u012852986/article/details/78873387
https://blog.csdn.net/Hubert_bing/article/details/55258280

猜你喜欢

转载自blog.csdn.net/u010982507/article/details/85258477