看完了理论Android HTTPS基础,HTTPS实际在Android中的是怎样应用的呢?

通过查看官方文档,通过 HTTPS 和 SSL 确保安全, 我们看到,访问HTTPS非常简单,系统已经完成了全部的工作,代码如下:

    URL url = new URL("https://wikipedia.org");    URLConnection urlConnection = url.openConnection();    InputStream in = urlConnection.getInputStream();    copyInputStreamToOutputStream(in, System.out);

没错,就这么简单。url.openConnection()根据请求URL区分返回的是HttpURLConnection还是HttpsURLConnection。只要你的服务器证书是由知名 CA 颁发的,Android系统内部会自动去验证服务器证书的有效性,建立起安全的连接。

如何从CA申请证书,可以参看阿里云证书申请。证书有免费的和收费的, 分为单域名,多域名,通配符域名等,可以从不同的知名CA中申请,例如Symantec赛门铁克, CFCA中国金融认证中心,GlobalSign, GeoTrust等等。申请完成后,部署在服务器就可以了。

如果我们只需要简单跑通代码,不需要往下看了,看看官网文档即可。下面是简单了解一下Android是怎样验证服务器证书的,以及自签名证书如何使用。

Android如何验证服务器证书?从前面HTTPS基础我们知道

如果某受信CA为"Sam的签名商店"签发了一个证书,而Sam的签名商店也签发了一个站点证书,浏览器可能会将其作为从有效CA路径导出的证书接受。

所以Android系统内置了很多知名CA的根证书,只要是该CA签发的证书(中间CA),以及中间CA签发的证书,形成了证书链,该证书链上的所有证书都是可信任的。
更详细Android源代码可参考Android 根证书管理与证书验证

除了看源代码,还可以如何观察验证证书过程呢?

HttpsURLConnection位于javax.net.ssl包下,提供了两个方法,可以传HostnameVerifier,SSLSocketFactory的类实例进去,HttpsURLConnection实例每次发起HTTPS请求都会调用这两个对象的方法。

public void setHostnameVerifier(HostnameVerifier v) {}public void setSSLSocketFactory(SSLSocketFactory sf) {}
public interface HostnameVerifier {    /**     * Verify that the host name is an acceptable match with     * the server's authentication scheme.     *     * @param hostname the host name     * @param session SSLSession used on the connection to host     * @return true if the host name is acceptable     */    public boolean verify(String hostname, SSLSession session);}

HostnameVerifier是用来查看要访问的域名是否正确,verify方法返回true则继续访问, 返回false则阻止访问。这里跟服务器证书没啥关系,仅仅是用来检查客户端的请求URL域名部分。

SSLSocketFactory是一个抽象类,继承SocketFactory。javax.net.SocketFactory就是一个创建普通Socket的抽象工厂类,看看源码就明白,没啥好说的。而SSLSocketFactory顾名思义,是创建基于SSL的安全Socket的抽象工厂类,它的实例的创建不是通过简单的继承,下面给出一个创建实例的方法:MyX509TrustManager.getSSLSocketFactory():

public class MyX509TrustManager implements X509TrustManager {    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};    @Override    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {    }    @Override    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {    }    @Override    public X509Certificate[] getAcceptedIssuers() {        return _AcceptedIssuers;    }    public static SSLSocketFactory getSSLSocketFactory() {        SSLContext context = null;        TrustManager[] trustManagers = new TrustManager[]{new MyX509TrustManager()};        try {            context = SSLContext.getInstance("TLS");            context.init(null, trustManagers, new SecureRandom());        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        } catch (KeyManagementException e) {            e.printStackTrace();        }        return context.getSocketFactory();    }}

X509TrustManager是一个接口,提供了验证服务器证书的checkServerTrusted方法,在这里面我们就可以检查服务端证书是否正确。

/**     * Given the partial or complete certificate chain provided by the     * peer, build a certificate path to a trusted root and return if     * it can be validated and is trusted for server SSL     * authentication based on the authentication type.     * 

* The authentication type is the key exchange algorithm portion * of the cipher suites represented as a String, such as "RSA", * "DHE_DSS". Note: for some exportable cipher suites, the key * exchange algorithm is determined at run time during the * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5, * the authType should be RSA_EXPORT when an ephemeral RSA key is * used for the key exchange, and RSA when the key from the server * certificate is used. Checking is case-sensitive. * * @param chain the peer certificate chain * @param authType the key exchange algorithm used * @throws IllegalArgumentException if null or zero-length chain * is passed in for the chain parameter or if null or zero-length * string is passed in for the authType parameter * @throws CertificateException if the certificate chain is not trusted * by this TrustManager. */ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException;

参数X509Certificate[] chain就是X.509 v3证书链,一般chain[0]就是根证书,chain[1]可能是中间证书,chain[2]就是服务器证书,取决于chain数组的长度,可以通过代码获取每个证书版本号,序列号,有效日期,CA签名,使用者名称,使用者公钥等等。

    @Override    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {        for (X509Certificate c : chain) {            Log.d("TAG", "c version:"+c.getVersion()+" SerialNumber:" + c.getSerialNumber()+                    " Principal:"+c.getIssuerDN().toString()+" X500Principal:"+c.getIssuerX500Principal().toString()+                    " getSubjectDN:"+c.getSubjectDN().toString() +                    " pb:" + GlobalUtils.getMD5(c.getPublicKey().getEncoded()));        }    }

如果不信任该证书,这里手动抛出异常即可,该连接就会断掉
如果需要自己处理来信任证书,比如自签名证书,也是在这里处理

我们可以看一下服务器证书一般是长啥样的,以win10系统,浏览器chrome访问百度https://www.baidu.com为例:
Android HTTPS实战1_第1张图片
Android HTTPS实战1_第2张图片
Android HTTPS实战1_第3张图片

参考:
volley源码
通过 HTTPS 和 SSL 确保安全
Android 根证书管理与证书验证
Android Https相关完全解析 当OkHttp遇到Https
X.509证书的解析、验证及使用
SSL证书原理讲解
关于SSL证书之证书链
https证书配置完整证书链常见问题

更多相关文章

  1. Android访问服务器出现W/System.err(9302): java.io.FileNotFoun
  2. Android数字签名获取证书指纹(SHA1)
  3. Android服务器搭建Git+Repo+Gerrit
  4. Android 中使用HttpUrlConnection实现get请求服务器
  5. Android(手机)连接电脑本地服务器(flask)

随机推荐

  1. Android图像篇
  2. Flash 之ANE的applicationDeployment.nat
  3. 开发Android应用 提升性能的小技巧
  4. Android Button应用法则
  5. 使用Android Studio 创建第一个Android
  6. 如何在Android和iOS设备上录制游戏?
  7. Android命令Monkey压力测试,详解
  8. android全平台编译ffmpeg合并为单个库实
  9. 修改版本号
  10. 让Python程序在Android手机上跑起来