由于2017年初开始禁止未使用https的应用上架appstore,领导们开始考虑在我们的应用中使用https,这让我很头疼,以前听到过https,用httpwatch抓知乎、微信的包的时候都看到这些应用使用的都是https,对https感觉很熟悉,其实是一知半解的,这下要在应用中使用,看来必须要好好研究下了。
下面是研究https在简书上搜索到的几篇优秀文章:
http://www.jianshu.com/p/ce1557c1868d;
http://www.jianshu.com/p/d79b37216558;
http://www.jianshu.com/p/4494774963a9;
http://www.jianshu.com/p/7cdd2324f639;
要使用HTTPS肯定要知道一些概念,从上面几篇优秀文章里找出来几个必须要了解的概念:
1.HTTP:一种明文传输协议,交互过程以及数据传输都没有进行加密,通信双方没有进行身份验证,通信过程容易遭到劫持、篡改的安全问题。
2.SSL:安全套接层。
3.HTTPS:只是一种在HTTP协议的基础上加了一层SSL的封装,之后具有了以下三个特征:
数据完整性:数据传输经过完整性校验
数据隐私性:数据经过加密
身份认证:第三方不能伪造客户端或者服务端的身份
4.对称加密:采用单密码加密,同一个密钥可以用来加密,也可以用来解密,简单理解就是加解密都是用的同一个秘钥。特点:体量小,算法公开,加密效率特别高。
5.非对称加密:有2个秘钥,一个是公开的秘钥,一个是私有密钥,这两个是一对,互相配合加密和解密,公钥加密用私钥解密,私钥加密公钥解密。特点:速度慢,但是加 密很可靠
6.CA 证书:其实就是XXX机构颁发的一个包含公钥和密钥的证书。
下面用一张我画的图来理解下HTTPS的工作原理:
第一步:client向service发送一条请求,告诉service,client支持哪种算法(比如:对称加密算法有DES,RC5,密钥交换算法有RSA和DH,摘要算法有md5和SHA等)
第二步:service接收到client的消息后,分析之后,选择一种client支持的算法,把证书发送给client的,这个证书里面包含了一些证书的基本信息(例如:失效时间,名称,域名信息,公钥等)
第三步:client接收到信息后,利用本地存在的数字证书对service的证书进行验证,如果验证失败,会弹出一个提示框来显示错误信息,验证通过,生成一个随机数,然后证书中的公钥进行加密,发送给service
第四步:service接收到加密的随机数之后,用公钥进行解密,取出随机数,然后把这个随机数当做密钥对要加密的内容进行对称加密,发送给client
第五步:client接收到service发送的密文,用之前保存的随机数作为密钥进行解密,还原密文
第六步:之后client和service进行数据交互,利用那个随机数作为密钥进行加解密
到这里对很多https的概念还是很迷茫,比如数字认证识什么东东,在第二步的时候client是怎么验证service的证书?,service怎么对client的身份做校验,然后就反反复复又查资料,上面的问题都可以在下面的博客中找到
http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html
现在应该能到得到一个结论,证书可以由国际上公认的证书机构颁发,一般客户端的证书验证的应用程序对这些机构颁发的证书完全信任,不过一般情况下,我们会让客户端程序安装我们服务端的根证书,保证客户端可以信任我们的证书。
好了,废话不多说,看代码
/** * 初始化有证书的SSLContext * <p> * client.cer 是后台申请提供的,不包含密钥信息 * * @param context * @return * @throws NoSuchAlgorithmException * @throws IOException * @throws CertificateException * @throws KeyStoreException * @throws UnrecoverableKeyException * @throws KeyManagementException */public static SSLContext getSSLContextWithCer(Context context) throws NoSuchAlgorithmException, IOException, CertificateException, KeyStoreException, UnrecoverableKeyException, KeyManagementException { //实例化SSLContext SSLContext sslContext = SSLContext.getInstance("SSL"); // 从assets中加载证书,在HTTPS通讯中最常用的是cer/crt和pem InputStream inputStream = context.getAssets().open("client.cer"); // 证书工厂 CertificateFactory cerFactory = CertificateFactory.getInstance("X.509"); Certificate cer = cerFactory.generateCertificate(inputStream); // 密钥库 KeyStore keyStory = KeyStore.getInstance("PKCS12"); //没有密钥 keyStory.load(null, null); // 加载证书到密钥库中 keyStory.setCertificateEntry("ass", cer); // 密钥管理器 KeyManagerFactory kMFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kMFactory.init(keyStory, null); // 信任管理器 TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmFactory.init(keyStory); //初始化sslContext sslContext.init(kMFactory.getKeyManagers(), tmFactory.getTrustManagers(), new SecureRandom()); inputStream.close(); return sslContext;}
/** * 获取SSLContext * * @return * @throws NoSuchAlgorithmException * @throws KeyManagementException */public static SSLContext getSSLContextWithoutCer() throws NoSuchAlgorithmException, KeyManagementException { // 实例化SSLContext SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, new TrustManager[]{trustManagers}, new SecureRandom()); return sslContext;}/** * 自定义信任管理器 */PRivate static TrustManager trustManagers = new X509TrustManager() { @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 new X509Certificate[0]; }};//验证主机名public static HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLsession session) { // TODO Auto-generated method stub return true; }};
新闻热点
疑难解答