OSI 模型
OSI
是 Open System Interconnection Reference Model
的缩写,意思是开放式系统互联通信参考模型
OSI
将计算机网络体系结构划分为7层,借用一下前人总结的模型图如下:
为方便快速理解,提取各层的关键字如下
应用层
HTTP、FTP、SMTP、POP3、DNS、DHCP、RPC 等
表示层
加密解密、转换翻译、压缩解压缩等
该层被弃用
会话层
该层被弃用
传输层
端口到端口、端口(16位二进制,0到1023被系统占用)、TCP (传输控制协议)、UDP(用户数据报协议)
SSL(安全套接字层协议)、TLS(传输层安全协议)
网络层
主机到主机、IP地址(32位二进制,4位十进制,网络部分+主机部分)、子网掩码、网关、路由协议
数据链路层
分为逻辑链路控制(logic link control,LLC)子层和介质访问控制(media access control,MAC)子层
PPTP(点对点隧道协议)、L2TP(第二层隧道协议)
以太网协议定义了帧、ARP(地址解析协议)、MAC地址(12位十六进制)、广播至本网络内所有计算机
物理层
传送0和1的电信号
通过 ARP
,可以得到同一子网内目标 IP
的 MAC
地址,例如:可以根据网关的 IP
得到网关的 MAC
地址
TCP/IP模型
OSI
是一种理论参考模型,而 TCP/IP
模型已被广泛使用,成为网络互联事实上的标准
TCP/IP
模型将计算机网络体系结构划分为4层,与 OSI
的对比如下:
上网4要素
- 本机IP
- 子网掩码
- DNS
- 网关
只有正确配置以上4要素,才能连接网络
配置的方式有两种:
- 设置静态IP
- 根据
DHCP
动态分配
域名解析
在浏览器中输入域名后,系统将进行域名解析,查询该域名对应的 IP
地址,查询步骤大致如下:
- 浏览器缓存,
url
为chrome://net-internals/#dns
- 系统缓存,命令
ipconfig /displaydns
hosts
文件,路径C:\Windows\System32\drivers\etc\hosts
,如果更改了此文件,使用命令ipconfig /flushdns
刷新DNS
解析缓存DNS
NetBIOS name Cache
,电脑上的缓存,保存着近期和本机成功通信过的IP
- WINS 服务器(是NETBIOS名称和IP地址对应的服务器)
- 广播查找
LMHOSTS
文件,路径C:\Windows\System32\drivers\etc\LMHOSTS.sam
TCP
3 次握手
建立TCP
连接时需要进行3次握手
TCP
握手进行3次的原因: 这样通信双方知道自己和对方都能收发信息
4 次挥手
关闭TCP
连接时需要进行4次挥手
TCP
挥手进行4次的原因:
- 一方关闭连接后,另一方仍可以发送数据
- 一方接收到另一方的关闭信号,要回传一个确认信号
- 两次来回总共4次挥手
Socket
Unix
系统把主机+端口,叫做"套接字"(Socket)。有了它,就可以进行网络应用程序开发了
这是系统封装了 TCP
连接,提供的上层接口,在执行 connect()
和 accept()
方法时进行 TCP
的3次握手
HTTP
Hypertext Transfer Protocol
的缩写,全称是超文本传输协议
默认使用80端口
HTTP
的内容很多,这里只略介绍请求和响应的基本格式
Request 格式
请求方法 URL 协议版本号 //请求行
Header1: Value1 //请求头
Header2: Value2
Header3: Value3
//空行
body //post请求有请求体
Response 格式
协议版本号 状态码 状态描述 //状态行
Header1: Value1 //响应头
Header2: Value2
Header3: Value3
//空行
body //响应体
当遇到连续两个 \r\n
时,Header部分结束,后面的数据全部是Body。
HTTPS
Http Over SSL
的缩写
默认使用443端口
非对称加密 (RSA) + 对称加密 ,可以防嗅探,但无法防范中间人攻击,这时候就需要CA证书
这也是抓包过程中如果想抓取 HTTPS
的数据就要安装并信任抓包工具的证书的原因
MITM (Man-In-The-Middle attack)—— 中间人攻击
CA(Certificate Authority)—— 数字证书认证机构
主流浏览器都内置了大部分可信的 CA
根证书,这些根证书中包含的公钥将用于服务端证书的检验
CA证书的主要内容
证书颁发机构的名称
证书本身的数字签名
证书持有者公钥
证书签名用到的Hash算法
SSL 握手
HTTPS
是在 SSL
握手阶段通过 “非对称加密” 协商出 “对称加密” 的秘钥,这个秘钥将用于后续的通信,这样同时兼顾了安全与效率
这个"握手阶段"涉及四次通信,"握手阶段"的所有通信都是明文的,流程大致如下:
- 客户端发起
HTTPS
请求,连接到服务端的443
端口,发送的内容主要包括:支持的协议版本、支持的加密算法、压缩算法、一个随机数k1
- 服务端返回的有:一个随机数
k2
、确认使用的加密通信协议版本(比如TLS 1.0
版本)、确认使用的加密算法(比如RSA
算法)以及服务端证书
如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书" - 客户端检验服务端证书是否可信:用浏览器内置证书的公钥解密证书,如果没有证书能解密,则证书是不可信的,如果解密成功则证书是可信的
- 客户端检验服务端证书是否被篡改:如果证书是可信的,则用相应证书的公钥对数字签名进行解密得到摘要A,然后再根据签名的Hash算法计算出证书的摘要B,对比A与B,若相等则正常,若不相等则服务端证书是被篡改过的
- 如果服务端证书是可信的且没有被篡改,则客户端生成一个随机数
k3
,然后取出证书中的公钥,用这个公钥加密k3
得到k30
并传给服务端,同时传送的还有:编码改变通知、客户端握手结束通知 - 服务端用自己的私钥解密
k30
得到k3
,回应客户端如下信息:编码改变通知、服务端握手结束通知
当客户端和服务端都有三个随机数 k1
、 k2
、 k3
时,双方就用商定的加密算法,各自生成本次会话所用的同一把"会话密钥"。
而使用3个随机数的原因是 一个伪随机可能完全不随机,可是三个伪随机就十分接近随机了,防止只使用一个伪随机被猜出秘钥
握手阶段结束后,客户端与服务器就进入加密通信,HTTP
内容在交给 TCP
之前都会被加密。
PSK (Pre-Shared Key) —— 预共享秘钥
在通信之前,通信双方部署若干共享的秘钥(通常是对称秘钥),每个秘钥一个ID。
客户端将自己选好的秘钥ID发送给服务端,服务端如果能在秘钥池中找到这个ID,就用对应的秘钥与客户端通信,否则报错并中断连接
Android中的https
当网络协议从 http
改为 https
,服务端就需要提供证书给客户端,用于校验。
如果服务端没有提供证书,就会直接报错。
如果服务端提供了证书,客户端就要进行校验,校验方式有以下两种:
-
通过
Android
系统校验证书
这是最简单的方式,客户端把http
改为https
就可以了,不用再做其他工作。只要是
Android
系统信任的证书,就可以通过校验,而系统会内置大部分可信的CA
根证书。这种情况下的抓包非常简单,只需要在手机设备上安装抓包工具的证书即可,这样抓包工具就能通过
Android
系统校验,拿到https
请求了。但从7.0版本开始,又没有这么简单了。
官网的版本更新记录——默认受信任的证书颁发机构,写了以下限制:
默认情况下,面向 Android 7.0 的应用仅信任系统提供的证书,且不再信任用户添加的证书颁发机构 (CA)。如果面向 Android N 的应用希望信任用户添加的 CA,则应使用网络安全性配置以指定信任用户 CA 的方式。
根据官方的描述,这种情况下想要抓包 https
请求,可以通过这几种方法:
-
targetSdkVersion 设为23及以下
-
在7.0以下系统抓包
-
使用网络安全性配置,指定信任用户添加的 CA
-
将用户添加的 CA 转变为系统 CA,这种方式一劳永逸,而且可以抓取设备上所有的
https
请求了。注意:抓包工具的 CA 证书,也可能因为有效期过长而不被信任(ERR_CERT_VALIDITY_TOO_LONG),因为为了安全,浏览器限制了证书的有效期时长。
Flutter中的https抓包
Flutter中的https抓包主要还需要解决两个问题:
1. Flutter中默认不使用手机设置好的网络代理,连不上抓包工具。
2. Flutter中默认不信任非可信根证书
签发的证书,即使抓包工具的证书在系统证书中,也是不可信的。
如果自己有Flutter源码,解决方式直接看下面的代码:
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
//代理设置
client.findProxy = (uri) {
return "PROXY host:port";
};
//抓Https包设置
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
};
这样设置后,即使抓包工具的证书不在系统证书中,也是可信的。
当然,我们没有别人 Flutter app 的源码,所以想抓包别人 Flutter app 的 https 请求,暂时无解。
2. app自己校验证书
app自己校验证书有两种方式:
-
Android 7.0 中新引入的说明性 网络安全性配置, 无需任何代码修改。
-
传统的易出错的编程 API(例如,X509TrustManager)。
这种情况下想要抓包
https
请求,就需要去研究app内部校验证书的逻辑,修改app代码达到目的。xposed下有个可用的模块JustTrustMe
服务端和客户端双向认证
除了客户端对证书对单向认证,更安全严格的就是服务端和客户端双向认证了,但ta在实际中几乎很少用到,因为服务器端需要维护所有客户端的证书,这无疑增加了很多消耗,这里不再细述了。银行U盾就属于这种校验方式。
参考资料:
互联网协议入门(一)——阮一峰
互联网协议入门(二)——阮一峰
维基百科-OSI模型
维基百科-TCP/IP协议族
OSI 7层模型和TCP/IP 4层模型
编程随想——扫盲https系列
一次完整的HTTP事务是怎样一个过程?
SSL/TLS协议运行机制的概述——阮一峰
图解SSL/TLS协议——阮一峰
图解HTTPS
详解https是如何确保安全的?