HTTP 协议 与 HTTPS
TCP/UDP 协议
TCP 协议
面向连接
TCP 协议是面向连接的,可靠的传输层协议,可以保证数据正确性和合法性,传输的可靠到达,流量控制。
在建立连接的时候,TCP 进行三次握手,释放连接的时候,进行四次挥手。
三次握手顺序如下:
- 客户端->服务端:我将发起连接。 服务端确定了自己的接收能力是 OK 的
- 服务端->客户端:我已经收到了你的请求。 客户端确定了自己的发送能力和接收能力
- 客户端->服务端:我接收到了你的回应,马上发送。 服务端确定了自己的发送能力。
四次挥手:
- 客户端->服务端:我没有数据发送了,你先发送剩下的,完事告诉我。
- 服务端->客户端:好的,我发送完了告诉你。
- 服务端->客户端:我发送完了,你收到信息就可以断开连接了。
- 客户端->服务端:好的,你也断开吧。客户端在等待一定时间保证网络上没有未到达的数据包后,断开连接。
为什么要四次挥手,因为客户端请求断开连接的时候,只是说明自己没有数据要发送了,但是自己还可以接受,服务端也可能还有数据没有发送完成。
所以 TCP 协议是面向连接的,它保证双方都有接受和发送能力。
数据可靠性和流量拥塞控制
- 校验和 有一个校验和字段,发送方将所有报文分段反码相加,结果存在校验和字段中,接收方收到后同样进行计算,相同则正确。
- 序列号 TCP 给每个字节都编号,进行去重、完整性、顺序性的应用。
- 确认应答 每次收到请求,接收方都会进行确认,给发送方发送确认报文,里面的确认值表明这个值之前的数据都收到了。
- 超时重传 经过一段时间后,发送方没有收到接收方的确认报文,会重新发送。
- 流量控制 接收方收到报文后,进行确认应答时,会将自身缓冲区剩余大小放到窗口段中,设置0的话,发送方不再发送数据,同时等待窗口更新的通知,过了超时时间还没有收到的话,会发送窗口探测,查看窗口是否更新完成可以继续发送。
- 拥塞控制、慢启动。还有一个拥塞窗口的概念,每次发送,都是发送流量控制窗口和拥塞窗口的最小值。每次拥塞窗口都是从1开始,指数级增长,慢慢发送的越来越多,超过阈值就进行线性增长,出现重传的话,阈值设置为当前拥塞窗口大小的一半,同时进行再次慢启动。
UDP 协议
UDP 协议无法保证可靠性,顺序性,所以传输效率高,处理速度快,所以通常音频和视频数据,可以使用 UDP 协议。
HTTP 协议
工作在应用层,基于 TCP 协议实现。
cookie
简单来说,服务器在响应头中给浏览器发送 Set-Cookie 段,后期浏览器根据段中的配置,取出 cookie 回传给服务器。每次可以发送多个段,每个段中包含:
* 名称-值 cookie 的名称和值
* Domain 域 = 域名 当前 cookie 可以被发送到哪些域或者子域下面 默认是当前域
* Path = 路径 所属的路径
* Expires = Date 过期时间未指定过期时间,代表生命周期为当前浏览器,关闭后删除,指定之前的时间,cookie 会立即删除。
还有一点,假如未设置过期时间,存储在浏览器内存中,否则存储在硬盘上。
* Secure 有这个字符串的话,代表只有 https 安全通信时才发送 cookie
* HttpOnly 有这个字符串的话,代表此 cookie 只能用于 http 或 https 传输,脚本 js 等是不能访问的。
浏览器回传给服务器的时候,在请求头发送 Cookie 段,只包含 名称=值 对,多个以分号相隔。
下面是一个例子:
1 | /// 服务器发送给浏览器,只注重 set-cookie 段 |
Cookie 可以做很多事情,因为浏览器已经保存起来了一些信息,比如用户账号缓存,记录用户行为,当然也有安全性缺失等缺点,比如 js 也可以更改存储的 cookie。
session
为了在 http 协议上,对客户保存状态,有两种方案,cookie 机制和 session 机制。
cookie 机制是在客户端保存状态的机制,而 session 是在服务端保持状态的一个机制。
当需要为客户端创建一个 session 的时候,服务器会检查客户端请求头中是否包含一个 session-id ,假如有的话就说明以前创建过 session ,根据 session-id 去查找到对应的 session ,假如没有的话,生成一个 session 和与之对应的 session-id,并把 session-id 返回给客户端保存起来。
通常,这个 session-id ,是保存在客户端的 cookie 里面的,但是有时候,客户端会把 cookie 禁止掉,这时候可以将 session-id 放到 url 后面上传。
至于在 session 里面可以存储什么,这个也是多种多样的。
HTTP 队首阻塞
在一个 tcp 连接中,只有多次请求会放到一个队列中,只有上一个请求收到回应完成后,才能发送下一个请求,这样假如前面的数据过大,会引起后面请求被阻塞。
HTTP 2.0
帧 消息 流
一个帧是传输数据的最小单位,里面有数据,有所属流的标识
流可以理解成针对于每个资源的请求
一个消息可以理解为一次 HTTP 传输的数据,里面可能包含多个流的多个帧。
每次传输一个消息,会一次传输多个流的多个帧,乱序传输,收到后会再次组合,这样实现了多个流即多个资源的并行传输,解决了 http 可能会出现的队首阻塞,但是 tcp 层的阻塞没有处理。
传输的数据被编码为二进制
数据被编码为二进制
多次连接复用一个 TCP 连接
建立一条 TCP 连接后,可能上面有多个数据流在并行传输。
首部压缩
不同于 http 1.x ,每次请求都有一个完整的 head 首部,http 2.0,保存着一个首部表,每次可能只对这个表进行键值对的更新,而且对于数据进行了压缩。
HTTPS:基于 HTTP 协议的加密实现
HTTP 协议的短板
- 因为 HTTP 协议是明文传输,所以有可能会被窃听
- 无法验证同新方的身份,可能遭遇伪装
- 无法证明报文的完整性,有可能已遭遇篡改
HTTPS 协议的解决方法
HTTPS 是 HTTP 通信接口部分使用 SSL 和 TLS 协议代替。
SSL 协议采用公开密钥加密的处理方式进行安全处理,HTTP 协议最开始直接和 TCP 通信,使用 SSL 后,变成先和 SSL 通信,再由 SSL 协议去和 TCP 进行通信。
采用 SSL 后,HTTPS 可以进行加密处理和认证,并进行完整性保护,即 HTTP + 加密 + 认证 + 完整性保护 = HTTPS。
所以说 HTTPS 并不是一种新的协议,而是 HTTP 采用 SSL 协议,SSL 协议提供这些加密等功能。
两种加密算法
共享密钥加密 和 公开密钥加密
- 共享密钥加密 也叫对称密钥加密,发送方和接收方都保存有一个密钥,加密和解密都用到密钥,但是如何传输密钥,传输过程中密钥也有可能会被监听窃取。
- 共开密钥加密 也叫非对称密钥加密,使用公开密钥加密,发送方使用接收方公布的公开密钥进行加密,接收方使用自己保存的私钥进行解密。
HTTPS 的具体实现方式
HTTPS 实现共享密钥加密和公开密钥加密结合的混合加密机制。
在传输共享密钥阶段,使用公开密钥加密方式进行交换密钥,之后简历通信交换报文,则使用共享密钥加密方式。
如何证明公开密钥的正确性
但是即使使用公开密钥加密,也有问题,那就是在交换公开密钥的时候,也无法证明公开密钥就是真正的密钥,有可能真正的公开密钥被替换掉了。
为了解决这个问题,引入了第三方数字证书认证机构,处于客户端和服务器双方都可信赖的第三方机构的立场上。
- 首先,服务器 A 运营人员向数字证书认证机构提出公开密钥的申请,把自己的公开密钥 a 发送给数字证书认证机构。
- 数字认证机构 B 用自己的私有密钥向服务器 A 的公开密钥 a 做数字签名,将这个公开密钥放入证书 b 。
- 服务器 A 会将这个证书 b 发送给客户端,客户端使用认证机构的公开密钥 b1,对这个证书的数字签名做验证,即验签操作,假如正确,客户端就认为服务器 A 发过来的证书中的公开密钥,是可以信任的。然后客户端发送数据的时候,使用服务器的公开密钥对报文加密后发送,服务器使用自己的私有密钥对报文进行解密。
这个过程有个前提,就是认证机构的 公开密钥 b1 ,是什么时候传输给客户端的,一般来说浏览器里事先导入了认证机构的公开密钥。
单向认证和双向认证
单向认证 客户端保存服务端的公钥,相当于只验证服务端是否安全。
双向认证 客服端保存服务端公钥,服务端保存客户端公钥,相互验证。
OC 如何实现 HTTPS
使用 NSURLSession
当使用 NSURLSession 发起时,会回调下面的方法:
1 | -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler |
使用 AF
AF 内部已经对 HTTPS 进行了处理,单向认证的时候:
1 | //在你封装的网络工具类请求前初始化时增加以下代码 |
双向认证的时候:
1 | //在你封装的网络工具类请求前初始化时增加以下代 |
Charles 如何进行的 HTTPS 抓包
Charles 抓取 HTTPS 的前提是客户端必须信任 Charles 证书。
使用 Charles 后:
- Charles 作为中间人,代替客户端向服务端请求数据。
- 服务端返回公钥证书后,Charles 将公钥保存,然后用自己的公钥制作证书,将证书发给客户端。
- 客户端获取 Charles 公钥证书后,必须选择信任,不然会中断连接,然后将对称加密私钥通过 Charles 公钥进行加密后传给 Charles。
- Charles 用自己的 私钥进行解密,获取到 对称加密私钥,然后用服务器的公钥进行加密传给服务器。
- 服务器用自己的私钥进行解密,获取到 对称加密私钥。
- 至此 Charles 获取到了 对称加密密钥 和 服务器公钥,就可以进行发送数据和解密了。
总结
相对于 HTTP 协议,HTTPS 会花费更多的时间,消耗更多的 CPU 资源,所以比较好的方式是在需要更安全的地方,使用 HTTPS 做数据传输。
单向认证更加灵活,客户端不需要把相应的证书打包进入 APP 内,这个证书是有过期时间的。
双向认证更加安全。