HTTPS 使用 SSL 在客户端和服务器之间进行加密通信,错误地使用 SSL ,将会导致其它人能够拦截网络上的应用数据。

使用一个包含公钥及与其匹配的私钥的证书配置服务器,作为 SSL 客户端与服务器握手的一部分,服务器将通过使用公钥加密签署其证书来证明自己具有私钥。

主机平台一般包含其信任的知名 CA 的列表。从 Android 4.2 开始,Android 包含在每个版本中更新的 100 多个 CA。CA 具有一个证书和一个私钥,为服务器发放证书时,CA 使用其私钥签署服务器证书。然后,客户端可以验证该服务器是否具有平台已知的 CA 发放的证书。

如果拥有一个知名 CA 发放证书的服务器,那么可以用以下代码直接发起 HTTPS 请求

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

对!就是这么简单。 Android 会对验证证书和主机名做处理,你不用考虑这些细节。

如果验证服务器证书出现 SSLHandshakeException 异常,那么原因可能是颁发服务器证书的 CA 是 Android 系统未知的,或者是自签署的服务器证书。

为了解决证书验证失败的问题,我们可以使用自定义的 TrustManager 使 HttpsURLConnection 信任特定的 CA 。

// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
} // Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca); // 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 context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null); // Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

InputStream 获取一个特定的 CA,用该 CA 创建 KeyStore,然后用后者创建和初始化 TrustManagerTrustManager 是系统用于从服务器验证证书的工具,可以使用一个或多个 CA 从 KeyStore 创建,而创建的 TrustManager 将仅信任这些 CA。

很多网站和博客介绍一种非常糟糕的解决方案来通过验证

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{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];
}
}}, null);
URLConnection urlConnection = url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

使用一个没有任何作用的 TrustManager。这样做等同于没加密通信,因为任何人都可以在公共 WLAN 热点下,使用伪装成服务器的代理发送数据,通过 DNS 欺骗攻击用户。然后,攻击者可以记录密码和其他个人数据。此方法之所以有效是因为攻击者可以生成一个证书,且没有可以真正验证证书是否来自值得信任的来源的 TrustManager,从而使你的应用可与任何人通信。

Android使用https与服务器交互的正确姿势的更多相关文章

  1. Android开发 - 获取系统输入法高度的正确姿势

    问题与解决 在Android应用的开发中,有一些需求需要我们获取到输入法的高度,但是官方的API并没有提供类似的方法,所以我们需要自己来实现. 查阅了网上很多资料,试过以后都不理想. 比如有的方法通过 ...

  2. 浏览器同部署了https的服务器交互的过程

    1 浏览器发起https请求 2 https服务器发送自己的公钥给浏览器 3 浏览器用https服务器发送过来的公钥加密一个用于双方通信的的对称密码 4 https服务器用自己的私钥解密,获取对称密码 ...

  3. Android开发中与服务器交互时,遇到java.io.IOException: Target host must not be null的问题

    当我遇到这个问题的时候,也在网上查找好半天.找到了一个和这个问题很类似的问题——java.lang.IllegalStateException: Target host must not be nul ...

  4. Git回退到服务器某个版本正确姿势

    背景: Git协作中,成员不可避免地会提交一些错误的版本,由于Git相比SVN引入了本地仓库,操作会相对复杂,以下为姿势分解 找一个源文件RspUtils.java,加上一行注释 //测试回退git服 ...

  5. Android玩转百度地图Sha1获取正确姿势?

    场景一 由于近期项目钟要用到定位功能因此肯定须要用到地图以及地位功能,相信大家也知道眼下国内比較出名的地图像百度.高德.腾讯等这些还是用到比較多的.于是思考了一下决定还是用百度,相信老司机们都知道的哈 ...

  6. [置顶] Android玩转百度地图Sha1获取正确姿势?

    场景一 由于最近项目钟要用到定位功能因此肯定需要用到地图以及地位功能,相信大家也知道目前国内比较出名的地图像百度.高德.腾讯等这些还是用到比较多的,于是思考了一下决定还是用百度,相信老司机们都知道的哈 ...

  7. 从高处理解android与服务器交互(看懂了做开发就会非常的容易)

    今天帮一个朋友改一个bug 他可以算是初学者吧 .我给他看了看代码,从代码和跟他聊天能明显的发现他对客户端与服务器交互 基本 不是很了解.所以我花了更多时间去给他讲客户端与服务器的关系.我觉得从这个高 ...

  8. android通过HttpClient与服务器JSON交互

    通过昨天对HttpClient的学习,今天封装了HttpClient类 代码如下: package com.tp.soft.util; import java.io.BufferedReader; i ...

  9. Android和FTP服务器交互,上传下载文件(实例demo)

    今天同学说他备份了联系人的数据放在一个文件里,想把它存到服务器上,以便之后可以进行下载恢复..于是帮他写了个上传,下载文件的demo 主要是 跟FTP服务器打交道-因为这个东东有免费的可以身亲哈 1. ...

随机推荐

  1. cc.Component 的使用

    1.组件入口函数,常有的:onLoad,start,update //组件在加载的时候运行,并且场景的初始化工作已经完成 onLoad() { }, //组件在第一次update调用之前调用 star ...

  2. 页面报错时隐藏Tomcat信息

    一.问题描述Tomcat报错页面泄漏Apache Tomcat/8.0.53相关版本号信息,是攻击者攻击的途径之一.因此实际当中建议去掉版本号信息. 二.解决办法1.进入到tomcat/lib目录下, ...

  3. spring boot vuejs

    项目介绍 Spring Boot 2.0 + VueJs 2.0 开发项目示例 GitHub: https://github.com/fqybzhangji/spring-boot-vue 码云: h ...

  4. 继承了AppCompatActivity的全屏设置

    v7下全屏设置:getSupportActionBar().hide();getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN ...

  5. 代码生成工具更新--快速生成Winform框架的界面项目

    在之前版本的代码生成工具Database2Sharp中,由于代码生成都是考虑Winform和Web通用的目的,因此Winform界面或者Web界面都是单独生成的,在工具中生成相应的界面后,复制到项目里 ...

  6. numpy array分割-【老鱼学numpy】

    有合并,就有分割. 本节主要讲述如何通过numpy对数组进行横向/纵向分割. 横向/纵向分割数组 首先创建一个6行4列的数组,然后我们对此数组按照横向进行切割,分成3块,这样每块应该有2行,见例子: ...

  7. rsyslog 移植与配置方案介绍

    rsyslog介绍 rsyslog是一个 syslogd 的多线程增强版.它提供高性能.极好的安全功能和模块化设计.虽然它基于常规的 syslogd,但 rsyslog 已经演变成了一个强大的工具,可 ...

  8. EL表达式与标签的使用

  9. Lesnoe Ozero 2016. BSUIR Open 2016 Finals

    A. Street magic 数位DP,设$f[i][j][k]$表示从低到高考虑$x$的后$i$位,$x$和$m$大小关系为$j$,和$n$大小关系为$k$的方案数. #include<cs ...

  10. js 复制(自动)

    <script type="text/javascript"> document.writeln("<input type=\'text\' id=\' ...