http
基础请求 - 请求标头 - 报文主体
- 基础请求:url | method | dest
- 请求标头:配置 + 拦截器 => 权限、身份
Accept - 请求内容的期望格式类型
text/
html: HTML 格式 / plain: 纯文本格式 / xml: XML 格式image/
gif: gif 格式 / jpeg: 图片格式 / png: png 格式video/
mpeg / quicktimeapplication/
xhtml+xml / atom+xml / json / pdf / msword / x-www-form-urlencoded
Accept-Encoding - 期望返回内容被压缩
- gzip, deflate, br,表示请求的返回希望被压缩,减少网络流量,提升性能。需要服务端支持,响应头中 Content-Encoding:gzip
Accept-Language - 浏览器所支持的语言 => 国际化、多语言包 zh 表示中文,zh-cn 表示简体中文;en、fr
Connection - TCP 信道的连接 keep-alive(1.1 之后默认) / close
Cookie - 缓存形式
- 集中缓存的对比 - cookie vs localStorage vs sessionStorage
大小:storage >> cookie
性能:cookie 每次请求都会携带,影响性能 => 网络性能优化
跨域:cookie 无法跨域调用,需要指定一个作用域 => 跨域问题
时效性:session - 当前页面;local - 跟随浏览器;cookie - 过期时间
跨 tab 共享:sessionStorage - 不支持;localStorage - 同源窗口共享;cookie - 同源窗口共享;
支持监听:session - 不支持跨页面,支持监听;local - 支持监听
- 集中缓存的对比 - cookie vs localStorage vs sessionStorage
Referer - 请求资源地址
User-Agent - 用户侧信息
Sec-Fetch-Dest\Sec-Fetch-Mode\Sec-Fetch-Site
- mode - 请求的模式
cors: 跨域请求
no-cors: 限制请求
same-origin: 同源请求
navigate: 浏览器切换页面行为
websocket: 建立 websocket 连接 - dest - 请求目标,如何使用获取的数据
empty / iframe / font / image - site - 请求发起者和资源之间的关系
cross-site: 跨域请求
same-origin: 发起方和目标一致
none
- mode - 请求的模式
q=0.01 - 参数优先级
- q 越高代表优先级越高 0 =< q <= 1 [0, 1]
- 默认不写,优先级 q = 1
http 攻击
SQL 注入 get get_name?a=encodeURLComponent(selectxXx)
xss(cross-site script) 转义
- 存储性 XSS 存储数据库,并且可以影响别人
- 反射性 xss alert selectxxX
- 基于 DOM 的 XSS script window.location
对策
- 编码:对用户的输入进行 HTML Entity 编码。
- 过滤:移除用户输入的和事件相关的属性。如 onerror 可以自动触发攻击,还有 onclick 等。(总而言之,过滤掉一些不安全的内容)移除用户输入的 style 节点、script 节点、Iframe 节点。
- 校正:避免直接对 HTML Entity 进行解码。使用 DOM parse 转换,校正不配对的 DOM 标签。
CSRF ( cross-site request forgery) 跨站点请求伪造
- A 登录 xianzao.com,保留 cookie
- 引导 zaoxian.com
- zaoxian.com 向 xianzao.com 发请求,xianzao.com/act=XXX,浏览器默认带有 xianzao.com cookie
- xianzao.com 接受请求,cookie,/act=xXX
- 在访问 zaoxian.com,攻击者在 A 不知情的情况下,伪造身份,请求 xianzao.com
对策
- Token 验证,用的比较多:① 服务器发送给客户端一个 token;② 客户端提交的表单中带着这个 token;③ 如果这个 token 不合法,那么服务器拒绝这个请求。
- 隐藏令牌:将 token 隐藏在 http 的 head 头中,方法二和方法一有点像,本质上没有太大区别,只是使用方式上有区别。
- Referer 验证:Referer 指的是网页请求来源,意思是,只接受本站的请求,服务器才做响应;如果不是,就拦截。
区别
- CSRF 需要用户先登录网站 A,获取 cookie,XSS 不需要登录。
- CSRF 是利用网站 A 本身的漏洞,去请求网站 A 的 api,XSS 是向网站 A 注入 js 代码,然后执行 js 里的代码,篡改网站 A 的内容。
http 状态码
- 1xx 信息提示: 表达服务器正在处理请求。100 - continue、 101 - 切换协议
- 2xx 成功:200 - 请求成功、201 - 创建完成、 204 - 无内容
- 3xx 重定向:301 - 永久重定向 / 302 - 对象已移动 /303 - 临时重定向/ 304 - 资源未修改 / 307 - 临时重定向
- 301 vs 302 => 跳转
302 - 短链接转长链接 => 点击短链接 => 对象已移动 => 浏览器自动跳转到长链接 302 vs 304 => 缓存
- 强缓存 => 不发请求 => 返回 200 状态码 + 标识 from cache
- 协商缓存 => 由服务端参考决定是否缓存
- 强缓存 => Expires(资源失效的时间) + cache-control (1.1) / max-age=3600 => cache-control > Expires
- 协商缓存 => Last-Modified(最后修改时间) + If-modified-Since + ETag => ETag 计算会有性能损耗
4xx - 请求错误
- 5xx - 服务端错误
get 和 post
- 协议层面:语义区别
- 应用层面:get 请求体为空
浏览器层面
- GET 在浏览器回退时是无害的,而 POST 会再次提交请求
- GET 产生的 URL 地址可以被 Bookmark,而 POST 不可以
- GET 请求会被浏览器主动 cache,而 POST 不会,除非手动设置
- GET 请求只能进行 url 编码,而 POST 支持多种编码方式
- GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留
- GET 请求在 URL 中传送的参数是有长度限制的,而 POST 么有
- 对参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有限制
- GET 比 POST 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息
- GET 参数通过 URL 传递,POST 放在 Request body 中
http 版本
v0.9
只有 get 方法
服务器只能回应 HTML 格式的字符串,不能回应别的格式。服务器发送完毕,就关闭 TCP 连接。
v1.0
每次建立断开连接消耗比较大
1.0 最大特点是增加了头部设定,请求头中 Accept 字段表示可以接收的文件类型,比如传输图像、视频、二进制文件。响应头中 Content-Type 字段 (MIME type 类型) 来告诉浏览器返回文件的类型
其他的新增功能还包括状态码 (status code) 、多字符集支持、多部分发送 (multi-part type) 、权限 (authorization) 、缓存 (cache) 、内容编码 (content encoding) 等
- 无状态
无长连接
- 早期 Http/1.0 性能上一个很大的问题,就是每发送一个请求,都要建立一次 TCP 三次握手,和 四次挥手。
无法复用连接
- 队头阻塞
- GET POST HEAD:请求方式少
- keep-alive => Connection:keep-alive (1.0 默认关闭)
v1.1
- keep-alive => Connection:keep-alive (默认的):规范的做法是,客户端在最后一个请求时,发送 Connection: close,明确要求服务器关闭 TCP 连接
- 支持长连接:TCP 连接复用,但是,本质上还是按照顺序发送
- 并发连接:对一个域名的请求允许分配多个长连接 (缓解了长连接中的「队头阻塞」问题)
- pipe:支持管道传输,一个 TCP 连接,可以同时发送多个请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能 够区分出每次请求的响应内容 (依然存在问题)
- 支持分块传输:Content-length:206
- PUT、HEAD、DELETE、OPTIONS、PATCH
- 新增了一些缓存的字段 (If-Modified-Since, If-None-Match)
- 请求头中引入了 range 字段,支持断点续传
- 允许响应数据分块 (Transfer-Encoding: chunked) ,利于传输大文件,否则就使用 Content-length 来区分数据包是属于哪一个回应的
- 强制要求 Host 头,让互联网主机托管称为可能 (可以将请求发往同一台服务器上的不同网站)
v2
由 SPDY 协议基础上继承而来
v 1.1 的性能问题
- 对头阻塞:使用持久连接时,一个连接中同一时刻只能处理一个请求。当前的请求没有结束之前,其他的请求只能处于阻塞状态
- 头部,冗余且未压缩
- 只能客户端发起
头部压缩:HPACK 算法。在客户端和服务器两端建立“字典”,用索引号表示重复的字符串,采用哈夫曼编码来压缩整数和字符串,可以达到 50%~90%的高压缩率
- 静态字典 :在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送
- 动态字典
- 首部表在 HTTP/2 的连接存续期内始终存在,由客户端和服务器共同渐进地更新
- 每个新的首部键值对要么被追加到当前表的末尾,要么替换表中之前的值
- 哈夫曼编码
二进制帧
v 1.1 为 ascll 文本 + 二进制 (报文的头信息必须是文本 (ASCII 编码) ,数据体可以是文本,也可以是 二进制)
- 将文本的格式,完全改成了 二进制帧的格式。
- 帧的好处,在于使用位运算进行高效解析。
并发传输,多路复用,避免队头阻塞
- 同一个 TCP 连接里面,客户端和服务器可以同时发送多个请求和多个响应,并且不用按照顺序来
- 多个 Stream 复用一条 TCP 连接,达到一个并发的效果
- 不同的 Stream 顺序可以不一致,在到达时,进行组装
服务端主动推送资源
http 1.1 使用 websocket 协议
- C — S 基数号 Stream
- S — C 偶数号 Stream
数据流
- 每个请求或者响应的所有数据包,称为一个数据流 (stream)
- 每一个数据流都有一个唯一的编号 ID,请求数据流的编号 ID 为奇数,响应数据流的编号 ID 为偶数
- 客户端还能指定数据流的优先级,优先级越高,服务器会越快做出响应
v3
v2 有哪些缺点
- TCP 协议本身的问题 (一个 TCP 连接进行传输,在丢包或网络中断的情况下后面的所有数据都被阻塞) ,队头阻塞;
- TCP 和 TLS 握手延迟;
- 网络歉意需要重新连接;
- 使用 QUIC + UDP (快速 UDP 互联网连接) 协议,取代 tcp 协议
- 严格要求加密
- 更快的连接建立:建立持久连接、协商加密协议,甚至发送第一批数据都被合并到 QUIC 中的单个请求/响应周期中,从而大大减少了连接等待时间
- 没有队头阻塞:通过 QUIC 连接传输的数据被分为一些流。流是持久性 QUIC 连接中短暂、独立的“子连接”。每个流都处理自己的错误纠正和传递保证,但使用连接全局压缩和加密属性。每个客户端发起的 HTTP 请求都在单独的流上运行,因此丢失数据包不会影响其他流/请求的数据传输
- 头部压缩,由 HPACK(61) 升级成 QPACK(91)
https
工作于 SSL 层 (Secure Sockets Layer 安全套接层) 之上的 HTTP 协议,传输层和应用层之间
基于 SSL 协议的互联网草案:传输层安全协议(TLS,Transport Layer Security)
SSL
位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。向应用层提供了两个基本安全服务:认证和保密。
- SSL 记录协议 (SSL Record Protocol) :为高层协议提供数据封装、压缩、加密等基本功能的支持 (进行数据加密并保证数据的完整性)
- 数据保密性:使用握手协议定义的秘密密钥对传送的数据加密
- 消息完整性:使用握手协议定义的带有 MAC 的密钥计算消息认证码
- SSL 握手协议 (SSL Handshake Protocol) :建立在 SSL 记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等 (服务器与客户端的认证与密钥交换)
- 建立安全能
- 服务端认证与密钥交
- 客户端认证与密钥交
- 完成握
- SSL 警报协议 (SSL Alert Protocol) :当客户机和服务器发现错误时,会向对方发送一个警报消息。如果是致命错误,算法立即终止会话并关闭 SSL 连接,同时删除相关会话记录、秘密和密钥
通信过程
- 客户端发送请求:当用户在浏览器中输入一个 HTTPS 网址时,客户端会向服务器发送一个请求,请求将它支持的 SSL 版本、加密算法、密钥交换算法、MAC 算法等信息发送给 SSL 服务器。
- 服务器回应:服务器确定本次通信采用的 SSL 版本和加密套件,并将携带自己公钥信息的数字证书通过 Certificate 消息发送给客户端,通知客户端版本和加密套件协商结束,开始进行密钥交换。
- 客户端验证证书并生成密钥:客户端验证服务器的证书合法后,利用证书中的公钥加密客户端随机生成密钥,并通知 SSL 服务器
- 客户端发送密钥:客户端使用已交互的握手消息的 Hash 值,利用协商好的密钥和加密套件处理 Hash 值 (计算并添加 MAC 值、加密等) ,发送给 SSL 服务器。
- 服务器解密密钥:服务器利用同样的方法计算已交互的握手消息的 Hash 值,并与 Finished 消息的解密结果比较,如果二者相同,且 MAC 值验证成功,则证明密钥和加密套件协商成功。
优缺点
- 优点:
- 使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器
- HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全,可防止数据在传输过程中不被窃取、修改,确保数据的完整性
- HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本
- 缺点:
- HTTPS 协议握手阶段比较费时,会使页面的加载时间延长近
- HTTPS 连接缓存不如 HTTP 高效,会增加数据开销,甚至已有的安全措施也会因此而受到影响
- HTTPS 协议的安全是有范围的,在黑客攻击、拒绝服务攻击和服务器劫持等方面几乎起不到什么作用
- SSL 证书通常需要绑定 IP,不能在同一 IP 上绑定多个域名,IPv4 资源不可能支撑这个消耗
- 部署 HTTPS 后,因为 HTTPS 协议的工作要增加额外的计算资源消耗,例如 SSL 协议加密算法和 SSL 交互次数将占用一定的计算资源和服务器成本
- HTTPS 协议的加密范围也比较有限。最关键的,SSL 证书的信用链体系并不安全,特别是在某些国家可以控制 CA 根证书的情况下,中间人攻击一样可行
http 的风险
安全性:http 超文本传输协议,信息是明文的,存在安全的问题
- 窃听风险;号没
- 篡改风险;眼没
- 冒充风险;钱没
https 是怎么解决这些问题的
- CA 证书:解决“冒充风险”
- 信息加密:解决“窃听风险”
- 校验机制:解决“篡改风险”
信息加密
混合加密
- 对称加密,对称加密只有,一个秘钥。运算速度很快,但是不够安全。
- 非对称加密,两个秘钥。公钥和私钥,公钥可以任意分发,私钥保密。但是速度慢。
CA 证书
- 公钥
- 持有者信息
- 证书认证机构信息
- CA 对这份文件的数组签名以及使用方法
- 证书有效期
- 额外信息
校验机制
- 明文:提取摘要 => 摘要 + 明文 一起加密
- 服务端用摘要算法加密,得到明文用摘要算法加密
- 若两次摘要相同,则内容无缺失
WebSocket
WebSocket 协议是 HTML5 的一种新协议,可实现浏览器/移动端和服务器建立全双工通信。
原理:WebSocket 同 HTTP 一样也是应用层的协议,但是它是一种双向通信协议,是建立在 TCP 之上的
目的:即时通讯,替换轮询。比如网页的 QQ,聊天系统等。按照以往的技术能力通常是采用轮询、Comet 技术解决。
vs http
- 相同点
- 都是一样基于 TCP 的,都是可靠性传输协议。 都是应用层协议。
- 区别:
- 连接方式:WebSocket 是双向通信协议,模拟 Socket 协议,可以双向发送或接受信息,是一种持久连接的协议。HTTP 是单向的,基于请求-响应模式。WebSocket 是需要握手进行建立连接的。
- 数据格式:HTTP 协议传输的数据一般采用明文的 ASCII 文本格式,通常是 HTML、JSON、XML 等格式的数据。而 WebSocket 协议可以传输任意格式的数据,包括二进制数据,可以更灵活地处理各种类型的数据。
- 通信效率:由于 HTTP 协议每次通信都需要经过完整的请求-响应过程,包括建立连接、发送请求、服务器处理请求、发送响应等步骤,因此在频繁通信的场景下,HTTP 的开销较大。而 WebSocket 协议在建立连接后只需要发送少量的头部信息,然后就可以直接进行数据传输,通信效率较高。
- 服务器推送:HTTP 协议是一种客户端主动发起请求的协议,服务器只能在收到请求后才能返回响应。而 WebSocket 协议支持服务器主动推送数据给客户端,服务器可以随时向客户端发送数据,实现实时通信。
- WebSocket 在建立握手时,数据是通过 HTTP 传输的。但是建立之后,在真正传输时候是不需要 HTTP 协议的。
- 性能比较:
- 吞吐量:WebSocket 相较于 HTTP 协议,在单位时间内能处理的请求数目更多,具有更高的吞吐量。
- 延迟:由于 WebSocket 是基于持久连接的全双工通信,相比于每次都需要重新建立连接的 HTTP 协议,WebSocket 的延迟更低。
- 适用场景:如果应用需要实时性较高的通信,如在线游戏、实时聊天等,WebSocket 是更好的选择。而对于传统的网页请求和响应,仍然可以使用 HTTP 协议。
Socket
- Socket 其实并不是一个协议(传输控制层),而是为了方便使用 TCP 或 UDP 而抽象出来的一层,是位于应用层和传输控制层之间的一组接口
- 当两台主机通信时,必须通过 Socket 连接,Socket 则利用 TCP/IP 协议建立 TCP 连接。TCP 连接则更依靠于底层的 IP 协议,IP 协议的连接则依赖于链路层等更低层次。
Cookie、Session、Token
Cookie
浏览器发起 HTTP 请求,服务器会进行 Cookie 设置,也就是 Set-Cookie
Cookie 里有名和值两个重要属性,服务器会把键和值属性里的内容给填充完整,Cookie 发送给浏览器以后,浏览器会保存起来,之后每一个请求都会自动附上这个 Cookie
sameSite:是否允许发送 cookie
- none:允许,但需要使用 https,设置 secure
- lax:默认值,组织发送 cookie,但对超链接放行
- strict:组织发送
Session
会话:浏览器访问服务器就是会话的开始,如何界定会话结束 (并非关掉网页的时间) ?
- 不同的网站对每个用户的回话都设定了时间以及唯一的 ID,就是通常所说的 Session ID, 这里的时间也就是结束会话的时间。保存在服务器中。
Token
- 用户第一次登录网页以后,服务器就会生成一个 JWT,服务器不需要保存这个 JWT,只需要保存 JWT 签名的密文,接着把 JWT 发给浏览器
- 浏览器以 Cookie 或者 Storage 的形式进行存储
JWT 组成
- header:声明需要用什么算法来生成签名
- payload:一些特定的数据,比如有效期之类的。header 和 payload 会经由 Base64 加密。默认字段:iss (发行人) 、exp (到期时间) 、sub (主题) 、aud (用户) 、nbf (在某个时间前不可用) 、iat (发布时间) 、jti (jwt id)
- signatuer:签名信息,由 服务器保存的一段密码(密钥) + header 的编码 + payload 的编码 通过第一步的算法生成
前端登录态保持
缘由:
- 最早的时候,web 的作用就是网页的浏览。 服务器只用提供简单的网页浏览器操作即可,不用记住刚刚谁发了请求,更没有登录,注册之类的操作
- http 设计之初就是无状态的
- http 无状态: http 不会记住每一次的请求 就跟公交车司机不会记住乘客一样
cookie+session
- 服务端登录的时候,给分配一个 session 用于存储数据,同时将 sessionID 返回给浏览器
- 浏览器通过 cookie 把 sessionID 存储起来,下次访问时携带上
- 服务端就可以通过 sessionID 来确定用户是否登录
缺点:服务端压力
- 每个人登录都需要在服务端开辟一块空间来信息,如果访问的人越来越多了,该怎么办
- 浪费了大量的内存,对于服务器来说是一个很大的开销
- 手机端很多浏览器不支持 cookie 或者是禁用 cookie
- 集群化不好实现
解决方案:集群 + session 持久化
- 增加更多服务器进行服务
- session 共享:在每一台服务器中都共享所有的用户信息
- 数据持久化:使用缓存 (redis/Memcached) ,将所有的 session 存储到数据库中,所有的 session 都统一去数据库中进行查找
token
优点:
- token 无状态,服务端不用存储 token,服务端只需要签发和校验 token 即可
- 集群:token 是无状态,集群的时候,算法一致,无论访问哪台服务器,都是一样的
- 性能: 解析 token 效率比查询数据库高的多
- 跨站点:只要服务端算法一致,token 就可以夸站点登录
- 移动端:在移动端开发中,使用 cookie 非常麻烦,使用 token 验证非常常见
使用方法:
- 客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage
- 此后,客户端每次与服务器通信,都要带上这个 JWT,放在 HTTP 请求的头信息 Authorization 字段里面 (放在 Cookie 里面不能跨域)
扫码登陆流程设计
- 生成二维码:首先,我们需要使用第三方库来生成二维码。在 JavaScript 中,可以使用 qrcode.js 库来生成二维码。具体使用方法可以参考该库的文档
- 后端生成登录标识:当用户扫描二维码后,我们需要后端生成一个唯一的登录标识,并将其存储到数据库中。这个登录标识将用于后续的登录验证
- 前端轮询检查登录状态:前端页面需要定时向后端发送请求,查询当前用户是否已经完成登录操作。可以使用 setInterval 函数来定时发送请求,并根据后端返回的登录状态进行相应的处理。
- 后端登录验证:当用户扫描二维码后,后端需要验证用户的登录操作。可以通过将登录标识与用户信息进行关联来进行验证
- 前端登录成功处理:当用户成功完成登录后,前端页面会收到后端返回的登录成功消息。此时,我们可以根据需要进行跳转或者其他相应的操作