diff --git a/notes/HTTP.md b/notes/HTTP.md index e6c6fc61..b6983f67 100644 --- a/notes/HTTP.md +++ b/notes/HTTP.md @@ -14,7 +14,7 @@ * [OPTIONS](#options) * [CONNECT](#connect) * [TRACE](#trace) - * [三、HTTP 状态码](#三http-状态码) + * [三、HTTP 状态码](#三http-状态码) 🔥 * [1XX 信息](#1xx-信息) * [2XX 成功](#2xx-成功) * [3XX 重定向](#3xx-重定向) @@ -27,7 +27,7 @@ * [实体首部字段](#实体首部字段) * [五、具体应用](#五具体应用) * [连接管理](#连接管理) - * [Cookie](#cookie) + * [Cookie](#cookie) 🔥 * [缓存](#缓存) * [内容协商](#内容协商) * [内容编码](#内容编码) @@ -36,9 +36,9 @@ * [多部分对象集合](#多部分对象集合) * [虚拟主机](#虚拟主机) * [通信数据转发](#通信数据转发) - * [WebSocket](#websocket) - * [跨域](#跨域) - * [六、HTTPS](#六https) + * [WebSocket](#websocket) 🔥🔥 + * [跨域](#跨域) 🔥 + * [六、HTTPS](#六https) 🔥🔥 * [加密](#加密) * [认证](#认证) * [TLS 握手](#tls-握手) @@ -50,7 +50,7 @@ * [二进制分帧层](#二进制分帧层) * [服务端推送](#服务端推送) * [首部压缩](#首部压缩) - * [HTTP/3](#http3) + * [HTTP/3](#http3) 🔥 * [九、GET 和 POST 比较](#九get-和-post-比较) * [作用](#作用) * [参数](#参数) @@ -222,7 +222,7 @@ TRACE 用于追踪路径,服务器会将通信路径返回给客户端。 通常不会使用 TRACE,并且它容易受到 XST 攻击(Cross-Site Tracing,跨站追踪)。 -## 三、HTTP 状态码 +## 三、HTTP 状态码 🔥 服务器返回的响应报文中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。 @@ -366,7 +366,7 @@ TRACE 用于追踪路径,服务器会将通信路径返回给客户端。 流水线是在同一条长连接上连续发出请求,而不用等待响应返回,这样可以减少延迟。但服务器必须按请求的顺序返回响应,前面的响应慢了,后面的都要等待,称为队头阻塞,加上很多代理处理不好流水线,主流浏览器都没有启用它。HTTP/2 用多路复用解决了这个问题,见 [二进制分帧层](#二进制分帧层)。 -### Cookie +### Cookie 🔥 HTTP 协议是无状态的,主要是为了让 HTTP 协议尽可能简单,使得它能够处理大量事务。可以使用 Cookie 来保存状态信息,Cookie 由 RFC 6265 单独定义,并不是 HTTP/1.1 的一部分。 @@ -797,10 +797,12 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名, 使用 SSL 等加密手段,在客户端和服务器之间建立一条安全的通信线路。 -### WebSocket +### WebSocket 🔥🔥 HTTP 是请求-响应模式,服务器不能主动给客户端发消息。聊天、实时通知这类场景以前只能轮询:短轮询定时发请求,大部分请求都是空的;长轮询让服务器挂起请求,直到有新消息再响应,但每条消息仍要一次新的请求。WebSocket 在一个 TCP 连接上提供全双工通信,建立连接后双方随时都可以发送消息。 +

+ WebSocket 连接由一次 HTTP 请求升级而来: ```text @@ -855,7 +857,7 @@ SSE 的局限: 只需要服务器单向推送时(例如大模型逐字输出),SSE 更简单;客户端和服务器都需要随时发消息时(例如聊天、协同编辑),使用 WebSocket。 -### 跨域 +### 跨域 🔥 同源指的是协议、域名和端口都相同。浏览器的同源策略限制网页中的脚本读取其它源的响应,例如 https://shop.example.com 页面中的脚本请求 https://api.example.com/orders,请求能够发出去,但浏览器默认不把响应交给脚本。 @@ -891,6 +893,8 @@ Access-Control-Max-Age 表示预检结果可以缓存的秒数,期间相同的 用两个端口模拟两个源验证(Edge 156 实测,见[附录 A3](#a3-跨域)):服务器不返回 Access-Control-Allow-Origin 时,fetch 失败,但服务器的日志显示请求已经执行了;预检请求没有允许 PUT 时,浏览器不再发送 PUT;携带 Cookie 而服务器返回 * 时,fetch 同样失败。 +

+ 需要注意的是,CORS 只决定浏览器是否把响应交给脚本,并不是安全措施:服务器仍然执行了请求,curl 这类不经过浏览器的工具也完全不受限制,权限要靠认证和 [CSRF 防护](攻击技术.md#二跨站请求伪造) 保证。另一种解决跨域的办法是同源的反向代理,例如由 Nginx 把 https://shop.example.com/api 转发给后端,浏览器看到的就是同源的请求。 其它做法: @@ -899,7 +903,7 @@ Access-Control-Max-Age 表示预检结果可以缓存的秒数,期间相同的 - WebSocket:握手请求不受同源策略限制,浏览器会带上 Origin 首部,服务器需要自己检查来源; - postMessage:不同源的页面之间(例如页面和其中嵌入的 iframe)通过它传递消息,接收方要检查消息的来源。 -## 六、HTTPS +## 六、HTTPS 🔥🔥 HTTP 有以下安全性问题: @@ -1028,7 +1032,7 @@ RSA 密钥交换没有前向安全:攻击者录下通信,日后拿到服务 Finished 报文的内容是用主密钥对此前全部握手报文的哈希值计算出的校验值(TLS 1.2 中为 12 字节)。握手的前几个报文是明文,攻击者可以篡改,例如删掉 ClientHello 中安全的密码套件,迫使双方使用弱算法,称为降级攻击。双方各自根据自己收发的报文计算校验值,报文被改过,两边的结果就对不上,握手失败。 -完整的握手要验证证书和签名,开销较大。客户端再次连接同一个服务器时可以恢复会话:服务器在握手后发给客户端一个会话票据(即上面 TLS 1.2 握手中的 NewSessionTicket),客户端下次连接时带上它,双方直接由之前协商的密钥派生出新的会话密钥,不再验证证书。TLS 1.3 恢复会话时,客户端还可以在第一个报文中就带上请求,称为 0-RTT。需要注意的是,0-RTT 的数据可以被攻击者录下后重放,服务器通常只对 GET 这类幂等的请求接受 0-RTT 数据。 +完整的握手要验证证书和签名,开销较大。客户端再次连接同一个服务器时可以恢复会话:服务器在握手后发给客户端一个会话票据(即上面 TLS 1.2 握手中的 NewSessionTicket),客户端下次连接时带上它,双方直接由之前协商的密钥派生出新的会话密钥,不再验证证书。TLS 1.3 恢复会话时,客户端还可以在第一个报文中就带上请求,称为 0-RTT。需要注意的是,0-RTT 的数据可以被攻击者录下后重放,通常只有 GET 这类安全的请求才放在 0-RTT 中发送。 #### 4. 一次 HTTPS 请求的过程 @@ -1109,7 +1113,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见

-### HTTP/3 +### HTTP/3 🔥 HTTP/2 在一个 TCP 连接上复用多个流,但 TCP 只保证整个字节流按序到达:一个报文段丢失时,后面已经到达的数据也要等它重传,所有的流都被阻塞,称为队头阻塞。 @@ -1119,6 +1123,8 @@ HTTP/3 改为基于 UDP 的 QUIC 协议: - QUIC 内置了 TLS 1.3,传输层握手和加密握手合并,新连接 1 个 RTT 后就能发送请求,恢复之前的会话时可以 0 RTT; - 连接用连接 ID 标识,而不是 IP 地址和端口,手机从 Wi-Fi 切换到移动网络时连接不用重建。 +

+ UDP 本身不保证可靠,QUIC 在它之上自己实现了确认、重传和拥塞控制,见 [在 UDP 上实现可靠传输](计算机网络%20-%20传输层.md#在-udp-上实现可靠传输)。 浏览器通常先用 HTTP/2 访问,从响应首部 Alt-Svc 得知服务器支持 HTTP/3 后再切换,例如 www.example.com 的响应中有 alt-svc: h3=":443"; ma=86400。 diff --git a/notes/pics/cors-cases.png b/notes/pics/cors-cases.png new file mode 100644 index 00000000..3459eedc Binary files /dev/null and b/notes/pics/cors-cases.png differ diff --git a/notes/pics/http3-quic.png b/notes/pics/http3-quic.png new file mode 100644 index 00000000..87b102ce Binary files /dev/null and b/notes/pics/http3-quic.png differ diff --git a/notes/pics/server-push-compare.png b/notes/pics/server-push-compare.png new file mode 100644 index 00000000..bd0f6118 Binary files /dev/null and b/notes/pics/server-push-compare.png differ