https = http +ssl 即基于于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护
## 优点
内容加密:采用混合加密技术,中间者无法直接查看明文内容
验证身份:通过证书认证客户端访问的是自己的服务器
保护数据完整性:防止传输的内容被中间人冒充或者篡改、
## 加密类型
先科普一下,加密算法的类型基本上分为了两种:
### 对称加密
**指加密和解密使用相同的密钥**
典型的有DES、RC5、IDEA(分组加密),RC4(序列加密);
### 非对称加密
**又称为公钥加密算法**,是指加密和解密使用不同的密钥(公开的公钥用于加密,私有的私钥用于解密
比如A发送,B接收,A想确保消息只有B看到,需要B生成一对公私钥,并拿到B的公钥。于是A用这个公钥加密消息,B收到密文后用自己的与之匹配的私钥解密即可。
反过来也可以用私钥加密公钥解密。也就是说对于给定的公钥有且只有与之匹配的私钥可以解密,对于给定的私钥,有且只有与之匹配的公钥可以解密
典型的算法有RSA,DSA,DH;
**由于非对称加密,有公钥也没有解密,也因此,相比较对称加密而言,非对称加密安全性更高,但是加解密耗费的时间更长,速度慢。**
### 散列算法
散列变换是指把文件内容通过某种公开的算法,变成固定长度的值(散列值),这个过程可以使用密钥也可以不使用。
这种散列变换是不可逆的,也就是说不能从散列值变成原文。因此,散列变换通常用于验证原文是否被篡改。
典型的算法有:MD5,SHA,Base64,CRC等
## CA 证书
### 关于证书:
服务端向客户端下发自己的证书,通常是CA认证的证书。证书包括了很多信息,主要有“公钥信息”、“签名”、“组织机构地区等信息”、“证书颁发机构”,关联的中级证书(medium certificate)、根证书(root certificate)等。
X.509 应该是比较流行的 SSL 数字证书标准,包含(但不限于)以下的字段:
| 字段 | 值说明 |
| --- | --- |
| 对象名称(Subject Name) | 用于识别该数字证书的信息 |
| 共有名称(Common Name) | 对于客户证书,通常是相应的域名 |
| 证书颁发者(Issuer Name) | 发布并签署该证书的实体的信息 |
| 签名算法(Signature Algorithm) | 签名所使用的算法 |
| 序列号(Serial Number) | 数字证书机构(Certificate Authority, CA)给证书的唯一整数,一个数字证书一个序列号 |
| 生效期(Not Valid Before) | (`・ω・´) |
| 失效期(Not Valid After) | (╯°口°)╯(┴—┴ |
| 公钥(Public Key) | 可公开的密钥 |
| 签名(Signature) | 通过签名算法计算证书内容后得到的数据,用于验证证书是否被篡改 |
**主要就是签名,用于验证是否篡改过**
### 客户端如何通过证书确定服务端的身份?
证明下面两点,(然后才可以使用证书上的公钥来加密生成Session key的随机数)
> 1. 证明baidu.com这个证书确实是百度的
> 2. 证明baidu.com这个证书没有被其他人攥改过
证书以证书链的形式组织,在颁发证书的时候首先要有根CA机构颁发的根证书,再由根CA机构颁发一个中级CA机构的证书,最后由中级CA机构颁发具体的SSL证书。
数字证书采用信任链验证。数字证书的信任锚(信任的起点)就是根证书颁发机构。根证书(root certificate)是一个无签名或自签名的证书。是用于识别根证书颁发机构(CA)的公钥证书。
验证的具体实现如下图所示: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f3cabb54bb904c70abcdb43ff345e15d~tplv-k3u1fbpfcp-watermark.awebp)
1. 从左往右,用户证书指向签署它的中级证书,并且,用户证书的摘要经由中级证书的私钥加密,密文作为该用户的证书签名(signature)记录在用户证书上。
2. 中级证书相应的,指向签署它的根证书,同时,中级证书的摘要经由根证书的私钥加密,密文作为中级证书的签名记录在中级证书上
3. 根证书在签署的时候,使用签发机构的私钥对证书的摘要进行加密,密文作为根证书的签名记录在根证书上。
**如何验证证书**
#### 1.如何验证证书没有被篡改过
比如验证用户证书A,需要用到中级证书的公钥B解密前者的签名得到摘要 Digest1,我们的客户端也计算A证书的内容得到摘要 Digest2。对比这两个摘要就能知道前者是否被篡改。后者同理,使用他的证书签发者提供的公钥验证。当验证到**到受信任的根证书**时,就能确定这个证书是可信的。
#### 2.为什么根证书是可信的
数字证书认证机构(Certificate Authority, CA)签署和管理的 **CA 根证书**,会被纳入到你的浏览器和操作系统的可信证书列表中,并由这个列表判断根证书是否可信。所以不要随便导入奇奇怪怪的根证书到你的操作系统中。
## HTTPS握手的过程
在 HTTPS 加密原理的过程中把对称加密和非对称加密都利用了起来,SSL协议是用非对称密码算法来协商密钥,并使用密钥加密明文并传输的
HTTPS大体分为以下几个步骤:
1. 验证证书的有效性(是否被更改,是否合法)
2. 握手生成会话密钥
3. 利用会话密钥进行内容传输
假设现在有客户端 A 和服务器 B :
1. 首先,客户端 A 访问服务器 B ,比如我们用浏览器打开一个网页https://www.baidu.com,这时,浏览器就是客户端 A ,百度的服务器就是服务器 B 了。
2. 时候客户端 A 会生成一个随机数1,把**随机数1 、自己支持的 SSL 版本号以及支持的加密**算法(譬如说,对称加密算法有DES,RC5,密钥交换算法有RSA和DH,摘要算法有MD5和SHA)等这些信息告诉服务器 B。
3. 服务器 B 知道这些信息后,然后确认一下双方的加密算法,”用DES-RSA-SHA这对组合好了“,**然后服务端也生成一个随机数 B ,并将随机数 B 和 CA 颁发给自己的证书一同返回给客户端 A。**
4. 客户端 A 得到 CA 证书后,会去校验该 CA 证书的有效性,校验方法在上面已经说过了。校验通过后,**客户端生成一个随机数3 ,然后用证书中的公钥加密随机数3 并传输给服务端 B 。**
5. 服务端 B 得到加密后的随机数3,然后利用私钥进行解密,得到真正的随机数3。
6. 最后,客户端 A 和服务端 B 都有**随机数1、随机数2、随机数3**,然后双方利用这三个随机数生成一个对话密钥。之后传输内容就是利用对话密钥来进行加解密了。这时就是利用了对称加密,一般用的都是 AES 算法,也就是上文约定好的协议。
7. 客户端 A 通知服务端 B ,指明后面的通讯用对话密钥来完成,同时通知服务器 B 客户端 A 的握手过程结束。
8. 服务端 B 通知客户端 A,指明后面的通讯用对话密钥来完成,同时通知客户端 A 服务器 B 的握手过程结束。
9. SSL 的握手部分结束,SSL 安全通道的数据通讯开始,客户端 A 和服务器 B 开始使用相同的对话密钥进行数据通讯。
到此,SSL 握手过程就讲完了。可能上面的流程太过于复杂,我们简单地来讲:
1. 客户端和服务端建立 SSL 握手,客户端通过 CA 证书来确认服务端的身份;
2. 互相传递三个随机数,之后通过这随机数来生成一个密钥;
3. 互相确认密钥,然后握手结束;
4. 数据通讯开始,都使用同一个对话密钥来加解密;
## 为什么一定要用三个随机数,来生成"会话密钥"?
答:不管是客户端还是服务器,都是下需要随机数,这样生成的密钥才不会每次都一样,由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出的密钥的随机性。
对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上第一步、第三步消息中的随机数,三个随机数通过一个密钥导出器最终导出一个对称密钥。pre master 的存在在于SSL协议不信任每一个主机都能产生完全的随机数,如果随机数不随机,那么pre master secret就可能被猜出来,那么仅适用于pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机数可能完全不随机,但是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。
### 中间人攻击与https抓包
一个针对SSL的中间人攻击过程如下:
![](https://img.kancloud.cn/33/31/3331bae6206f6c66cc109cc44972154f_882x867.png)
中间人其实是做了一个偷梁换柱的动作,核心是如何欺骗客户端,从而让客户端能够放心的与中间人进行数据交互而没有任何察觉。我们来看Charles如何做到HTTPS抓包的,网上有很多fiddlers如何抓HTTPS包的教程,几步就搞定了,其中最核心的就是:
**将私有CA签发的数字证书安装到手机中并且作为受信任证书保存**
当私有的CA证书添加到系统信任证书后,就可以完成证书链验证过程
fiddler抓包过程,详情可见:[www.cnblogs.com/afeng2010/p…](https://link.juejin.cn?target=https%3A%2F%2Fwww.cnblogs.com%2Fafeng2010%2Fp%2F10073446.html "https://www.cnblogs.com/afeng2010/p/10073446.html")
#### android7.0之后用户CA限制
Android从7.0开始系统不再信任用户CA证书(应用targetSdkVersion >= 24时生效,如果targetSdkVersion = 24的应用的HTTPS包就抓不到了。
Android 6.0(API 23)及更低版本应用的默认网络安全性配置如下:
~~~java
<!-- 默认允许所有明文通信 -->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- 信任系统预装 CA 证书 -->
<certificates src="system" />
<!-- 信任用户添加的 CA 证书,Charles 和 Fiddler 抓包工具安装的证书属于此类 -->
<certificates src="user" />
</trust-anchors>
</base-config>
~~~
而在 Android 7.0(API 24)到 Android 8.1(API 27)的默认网络安全性配置如下:
~~~java
<!-- 默认允许所有明文通信 -->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- 信任系统预装 CA 证书 -->
<certificates src="system" />
</trust-anchors>
</base-config>
~~~
而在 Android 9.0(API 28)及更高版本的默认网络安全性配置如下:
~~~java
<!-- 默认禁止所有明文通信 -->
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<!-- 信任系统预装 CA 证书 -->
<certificates src="system" />
</trust-anchors>
</base-config>
复制代码
~~~
如果我们要抓自已APP的包,解决方式就是使用 Android 6.0 以下的网络安全性配置: 添加res/xml/network\_security\_config.xml:
~~~java
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
~~~
然后在清单文件中指向该文件:
~~~java
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config"
... >
...
</application>
</manifest>
~~~
### 如何防止中间人攻击
通过上面的讲解,大家可以知道
假设你的设备没有安装信任过来历不明的证书,那么不管在任何WIFI或者网络环境下,通常HTTPS通信都是安全的
并且在android7.0及以上,就算手机安装信任了证书,在一般情况下也是安全的,因为android7.0以上默认不信任用户证书
所以通常情况下,我们不需要做什么特别操作来防止中间人攻击
不过有部分金融类的APP需要额外校验来保证https的安全性
我们可以下载服务器端公钥证书,然后将公钥证书编译到Android应用中一般在assets文件夹保存,由应用在交互过程中去验证证书的合法性。
~~~java
//使用内置证书
public static SSLSocketFactory getSSLSocketFactory_Certificate(Context context) {
try {
//获取X.509格式的内置证书
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
Collection<? extends Certificate> cers = certificateFactory.generateCertificates(context.getAssets().open("CACertificate.cer"));
int index = 0;
for (Certificate certificate : cers) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
//用这个KeyStore去引导生成的TrustManager来提供验证
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
//用TrustManager生成SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
//SSLContext返回SSLSocketFactory
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
~~~
## 参考资料
[https加密原理](https://blog.csdn.net/fei20121106/article/details/84104843)
[Android程序员需要了解的https与中间人攻击](https://juejin.cn/post/6880024440143347719)
- Android
- 四大组件
- Activity
- Fragment
- Service
- 序列化
- Handler
- Hander介绍
- MessageQueue详细
- 启动流程
- 系统启动流程
- 应用启动流程
- Activity启动流程
- View
- view绘制
- view事件传递
- choreographer
- LayoutInflater
- UI渲染概念
- Binder
- Binder原理
- Binder最大数据
- Binder小结
- Android组件
- ListView原理
- RecyclerView原理
- SharePreferences
- AsyncTask
- Sqlite
- SQLCipher加密
- 迁移与修复
- Sqlite内核
- Sqlite优化v2
- sqlite索引
- sqlite之wal
- sqlite之锁机制
- 网络
- 基础
- TCP
- HTTP
- HTTP1.1
- HTTP2.0
- HTTPS
- HTTP3.0
- HTTP进化图
- HTTP小结
- 实践
- 网络优化
- Json
- ProtoBuffer
- 断点续传
- 性能
- 卡顿
- 卡顿监控
- ANR
- ANR监控
- 内存
- 内存问题与优化
- 图片内存优化
- 线下内存监控
- 线上内存监控
- 启动优化
- 死锁监控
- 崩溃监控
- 包体积优化
- UI渲染优化
- UI常规优化
- I/O监控
- 电量监控
- 第三方框架
- 网络框架
- Volley
- Okhttp
- 网络框架n问
- OkHttp原理N问
- 设计模式
- EventBus
- Rxjava
- 图片
- ImageWoker
- Gilde的优化
- APT
- 依赖注入
- APT
- ARouter
- ButterKnife
- MMKV
- Jetpack
- 协程
- MVI
- Startup
- DataBinder
- 黑科技
- hook
- 运行期Java-hook技术
- 编译期hook
- ASM
- Transform增量编译
- 运行期Native-hook技术
- 热修复
- 插件化
- AAB
- Shadow
- 虚拟机
- 其他
- UI自动化
- JavaParser
- Android Line
- 编译
- 疑难杂症
- Android11滑动异常
- 方案
- 工业化
- 模块化
- 隐私合规
- 动态化
- 项目管理
- 业务启动优化
- 业务架构设计
- 性能优化case
- 性能优化-排查思路
- 性能优化-现有方案
- 登录
- 搜索
- C++
- NDK入门
- 跨平台
- H5
- Flutter
- Flutter 性能优化
- 数据跨平台