HTTP 基础/连接/授权
基础
请求方法
请求方法 | Body | 幂等 | |
---|---|---|---|
GET | 获取资源 | Y | |
POST | 增加或修改资源 | Y | |
PUT | 修改资源 | Y | Y |
DELETE | 删除资源 | Y | |
HEAD | 同 GET;响应报文没有 Body | 响应报文也没有 | Y |
状态码
状态码 | 描述 |
---|---|
1xx | 临时消息 |
100 | 继续发送 |
101 | 协议切换 e.g. http1.1 -> http2 |
2xx | 成功 |
3xx | 重定向 |
4xx | 客户端错误 |
5xx | 服务器错误 |
Header
-
Header: 用于主机确定子主机,不用于 DNS 解析。
-
Content-Length: Body 长度。Body 可能包含任意数据,包括二进制数据。因此难以设置一个结束标记。所以需要显式指明数据长度。
-
Content-Type:
-
text/html: html 文本,用于浏览器页面响应。
-
application/x-www-form-urlencoded: 普通表单(纯文本表单),URL encoded 格式。
[body] key1=v1&key2=v2
-
multipart/form-data: 多部分形式。多用于传输包含二进制项的多项数据。
POST /users HTTP/1.1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary777777 ----WebKitFormBoundary777777 ......
-
application/json
-
application/zip, image/jpeg...: 单文件,多用于响应或 POST/PUT 请求。
-
-
Location: 重定向目标 URL
-
Range: 指定 Body 内容范围。用于分段加载/断点续传。服务器用 Accept-Ranges 指明是否支持,以及支持的单位。
Range: bytes=0-1024
-
Cookie / Set-Cookie
-
Authorization
登录与授权
Authorization
Authorization
是一个 HTTP Header,根据具体使用的规范不同,携带不同的数据来认证。
Basic
Header 格式:
Authorization: Basic xxxxxx(<username:password> 整体 base64 编码)
缺点
- 明文传输 (http) 易泄漏密码。
- 一旦泄漏不易撤销授权(需要改密码)。
Bearer
Header 格式:
Authorization: Bearer <token>
此处的 Token 一般来源于:
- 第三方授权提供(OAuth),用于向 Provider 请求用户数据。
- 自家服务生成,用于客户端与服务器通讯。
OAuth2
在场景 「用户使用 Github 登录掘金」 中:
- 第三方登录:Github 为第三方。(这是一个不规范的名词)
- 第三方授权:掘金为第三方。本质是 Github 授权掘金获取用户的数据。
sequenceDiagram
autonumber
participant S as 3rd-party Server
participant B as 3rd-party Client
participant P as Provider
B->>P: client_id
P->>B: authorization_code
B->>S: authorization_code
S->>P: authorization_code & client_secret
P->>S: access_token & refresh_token
-
① 跳转到 Provider 的网站。
client_id
用于 Provider 确认第三方身份。 -
②: OAuth 不强制使用 https(也无法保证浏览器本身不是恶意软件),故这里只返回 code 而不是 token,防止被窃取。
AuthCode 换取 token 的时候需要 client_secret,所以即使 AuthCode 被窃取也依然安全。
-
⑤: 第三方得到 token,OAuth2 流程结束。
refresh_token
出于安全目的提供,防止 access_token 泄漏。可以立即刷新 access_token,或在其过期后自助重新获取。
原则上 access_token 不应该发送到客户端,客户端不应该自己去 Provider 取数据。
TCP/IP 协议族
分层
-
应用层/Application Layer
-
传输层/Transport Layer:提高传输稳定性,为应用层提供数据切分分块传输/重传能力。
-
网络层/Internet Layer:不是所有的场景都需要重传,但它们都需要网络(寻址/路由等),因此抽象出网络层。
-
数据链路层/Link Layer:不同的物理设备/传输介质需要不同的协议,因此抽象出数据链路层。
TCP 连接
建立连接
TCP 是有状态协议,需要建立连接。为了节省资源,也需要关闭连接。
sequenceDiagram
autonumber
participant C as Client
participant S as Server
C->>S: SYN=1
activate C
Note left of C: SYN_SEND
S->>C: SYN=1, ACK=1
deactivate C
activate S
Note right of S: SYN_RCVD
C->>S: SYN=0, ACK=1, DATA
deactivate S
Note left of C: ESTABLISHED
Note right of S: ESTABLISHED
关闭连接
sequenceDiagram
autonumber
participant C as Client
participant S as Server
C->>S: FIN=1
activate C
Note left of C: FIN_WAIT_1
S->>C: ACK=1
deactivate C
activate S
activate C
Note right of S: CLOSE_WAIT <br/>半关闭:客户端不再发送数据
Note left of C: FIN_WAIT_2
S->>C: FIN=1, ACK=1
deactivate C
deactivate S
activate S
Note right of S: LAST_ACK<br/>服务端不再发送数据
C->>S: ACK=1
deactivate S
activate C
activate S
Note right of S: CLOSED
Note left of C: TIME_WAIT<br/>2MSL
deactivate C
activate C
Note left of C: CLOSED
deactivate C
deactivate S
长连接
TCP 连接若长时间空闲,网关或中间的其他网络节点可能会强行关闭来释放资源。
但实际上不发消息不代表打算关闭连接,随时有可能出现新消息。
所以我们要定期发送一点消息来保持活跃,称为「心跳包」。
心跳包的频率等问题,需要在稳定/耗电等诸多方面寻求平衡,是一个专门的话题。
HTTPS 连接
HTTPS 本质是在 HTTP 与 TCP 直接插入一个加密层。它在客户端与服务器之间用非对称加密协商出一个对称加密密钥,用这个密钥加密后续的数据。
HTTPS (TLS) 也是有状态的(比如协商出的对称密钥),同样需要连接。
基本流程
- 客户端请求建立 TLS 连接
- 服务器发回证书
- 客户端验证证书
- 协商对称密钥
- 开始加密通讯
sequenceDiagram
autonumber
participant C as Client
participant S as Server
C->>S: Client Hello 0x01 etc..
S->>C: Server Hello 0x02 etc..
S->>C: Cert etc..
C->>S: Pre-master secret (服务器公钥加密)
C->>S: Finish
S->>C: Finish
-
①: 除了握手包,也包括可选的 TLS 版本 / 加密套件 Cipher suites(可选的对称/非对称/hash 算法)/ 一个随机数。
-
②: 除了服务端握手包,还包括选定的 TLS 版本 / 加密套件 / 一个服务端生成的随机数。
-
③: 服务器发送:
- 自己的证书(包括:公钥/主机名/签名等)
- 用于签名的私钥对应的证书(证书签发机构的证书)
- ...
- 根 CA 的信息
-
④: 发送后。双方都可以使用 Pre-master-secret + Client-random + Server-random 计算出 Master-secret。
为什么不直接用 pre-master 作为密钥?
防止重放攻击 (replay attack)
之后,双方也都可以通过 Master-secret 推算出这些数据:
- 客户端密钥
- 服务端密钥
- 客户端 MAC secret
- 服务端 MAC secret
为什么 TLS 中客户端与服务端要使用不同的密钥?
防止黑客把客户端的数据原样发回。此消息密码正确,会被误认为是服务器返回的。
什么是 MAC secret?
HMAC: hash-based message anthenticate code. 在 hash 的过程中添加进去一个密钥,一遍确认执行 hash 的人身份。
-
⑤: 客户端通知服务器即将发送加密信息;将上面几步的数据结合在一起加密/HMAC 发送。
-
⑥: 服务器通知客户端即将发送加密信息;将上面几步的数据结合在一起加密/HMAC 发送。