HTTP
2022-08-01 15:53:04 2 举报
AI智能生成
登录查看完整内容
包含了 http 协议的发展,历史,从 HTTP1.0 到 HTTP3.0 的总结
作者其他创作
大纲/内容
消息往返时延
表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延
RTT
前置知识
1989 年蒂姆·博纳斯-李的一篇论文
URI: 统一资源标识符
HTTP 起始
20 世纪 90 年代
采用了纯文本格式
只允许\"GET\
HTTP/0.9
正式发布于 1996 年
增加了 HEAD、POST 等新方法
增加了响应状态码
引入了协议版本号概念
引入了 HTTP Header 概念
传输不再仅限文本
主要变更
HTTP/1.0
正式成为了标准
增加 PUT、DELETE 等新方法
增加缓存管理和控制
强制要求 Host 头
开启了 Web1.0 和 Web2.0 时代
从纯文本到二进制协议
允许服务器主动向客户端推送数据
性能改善
HTTP/1.1
2015 年发布 HTTP/2 RFC 编号 7540
以 Google 的 SPDY 为基础指定的新版本的 HTTP 协议
衍生出 gRPC 等新协议
HTTP/2
HTTP/3
前世今生
全称
HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范
超文本
HTTP 是一个在计算机世界里专门用来在两点之间传输数据的约定和规范
传输
协议
HTTP 是什么
不是互联网
不是编程语言
不是 HTML
不是孤立的协议
HTTP 不是什么
HTTP 通常跑在 TCP/IP 协议栈之上依靠 IP 协议实现寻址和路由TCP 协议实现可靠数据传输DNS 协议实现域名查找SSL/TLS 协议实现安全通信
HTTP 是什么/不是什么
全称:Content Delivery NetWork
运用了 HTTP 协议里的缓存和代理技术
负载均衡
安全防护
周边计算
跨运营商网络
加速访问
作用
位于浏览器和服务器之间
CDN
网络应用防火墙
位于 Web 服务器之前
主要检测 HTTP 流量
WAF
互联网大部分资源都使用 HTTP
总结
与 HTTP 相关的各种概念
是一系列网络协议的统称
应用层
链接层
协议栈
Internet Protocol
分为 V4 和 V6 两个版本
V4 使用\".\
V6 使用 8 组\":\
IP 协议
Transmission Control Protocol \"传输控制协议\"
HTTP 全称: HTTP over TCP/IP
TCP 协议
TCP/IP
域名系统(Domain Name System)
DNS
统一资源标识符
唯一的标记互联网上的资源
http
协议名
nginx.org
主机名
/etc/download.html
路径
构成
URI
统一资源定位符(网址)
URI 的子集
URL
URI/URL
全称: HTTP over SSL/TLS
HTTP 全称: HTTP over TCP/IP
负责加密通信的安全协议
建立在 TCP 之上
可靠的传输协议
全称: Secure Socket Layer
SSL/TLS
HTTPS
Proxy
作为 HTTP 请求方和应答方中间的中转站
匿名代理
透明代理
正向代理
反向代理
把访问请求均匀分散到多台机器,实现访问集群化
暂存上下行的数据,减轻后端的压力;
内容缓存
提供压缩、加密等额外的功能
数据处理
中间层
分类
HAProxy代理软件定制
不属于 RFC 标准
代理协议 Proxy Protocol
代理
与 HTTP 相关的各种协议
有层次的协议栈
面向各种具体应用协议
application layer 应用层
负责保证数据在 IP 地址标记的两点之间\"可靠\"传输
TCP 是连续的\"字节流\
也叫 TCP 层
transport layer 传输层
用 IP 代替 MAC 地址
也叫 IP 层
Internet layer 网际层/网络互联层
负责在底层网楼哦上发送原始数据包
工作在网卡层
使用 MAC 地址标记网络设备
也叫 MAC 层
link layer 链接层
分层
HTTP 的单位是 消息/报文 message
TCP 层是 段 segment
IP 层是 包 packet
MAC 层是 帧 frame
传输单位(统称数据包)
TCP/IP 网络分层模型(四层模型)
全称: 开放式系统互联通信参考模型(Open System Interconnection Reference Model)
面向具体应用传输数据
应用层
表示层
会话层
相当于 TCP/IP 的传输层
传输层
相当于 TCP/IP 的网际层
网络层
基本相当于 TCP/IP 的链接层
数据链路层
物理层
OSI 网络分层模型(七层模型)
OSI 中五六七层分的太细
第五六七层: 统一对应到 TCP/IP 的应用层
两个分层模型的映射关系
就是分摊到多个操作单元上执行
啥叫负载均衡
在传输层上
基于 TCP/IP 协议特性
四层负载均衡
在应用层上
七层负载均衡
所谓负载均衡
网际层/IP 层: 再加一层 IP 地址
链接层/MAC 层: 加一层 MAC 地址
TCP/IP 协议栈工作方式
凡是由操作系统负责处理的就是四层或四层以下
凡是需要应用程序负责的就是七层
区分四层和七层的方法
四层和七层的区别
域名是有层次的
用一串\".\"来分割
最右边的是\"顶级域名\"依次递减叫\"二级域名\
域名的形式
代替 IP 地址
域名的作用
域名解析必须通过 DNS
管理顶级域名的服务器 \".com .cn .org\"
根域名服务器(Root DNS Server)
顶级域名服务器(Top-level DNS Server)
权威域名服务器(Authoritative DNS Server)
DNS 的核心是一个三层的树状、分布式服务
缓存
某个域名如何解析我说了算
权威域名服务器
需要访问 DNS 解析系统去获取各个域名的解析结果
非权威域名服务器(\"野生\" DNS 服务器)
Linux 在 /etc/hosts
windows 在 c:\\windwos\\system32\\drivers\\etc\\hosts
HOST 文件映射
DNS 分为几种
浏览器缓存
在系统缓存中查找
找到了返回并同步缓存
操作系统DNS缓存
特殊文件,不缓存任何 DNS,除非手动添加
HOSTS 文件
非权威域名服务器
根域名服务器
就去二级域名查看(这里去不去二级域名服务器主要是看有没有主机名)
没有主机名就逐层返回并且逐层同步缓存
通过顶级域名来 \"google.com\
顶级域名服务器
二级域名服务器
域名解析过程
域名的解析
一、重定向
二、内部 DNS 服务器
三、基于域名实现负载均衡
四、域名屏蔽
如 hosts 中 把某些软件的地址给设置成 127.0.0.1
五、域名劫持
域名的新玩法
域名里的门道
地址栏输入 \"127.0.0.1\"
三次握手依次是 SYN 、SYN/ACK、ACK 三个包
浏览器与服务器的 TCP 连接建立起来了
一、建利 TCP 连接
二、HTTP 通过 TCP 发送 \"GET/HTTP/1.1\" 请求报文
三、Web 服务器 TCP 协议层回复浏览器 ACK 确认
四、Web 服务器收到报文后再内部处理这个请求
五、把根据浏览器的请求将需要的东西发回去通过 TCP 发送 \"HTTP/1.1 200 OK\"
六、浏览器给服务器回复 TCP 的 ACK 确认收到
四次挥手依次是
浏览器向服务器发送 FIN 断开信号
服务器发送 ACK 确认
服务器发送 FIN 断开信号
浏览器向服务器发送 ACK 确认
八、四次挥手断开 TCP 连接
使用 IP 地址访问 Web 服务器
使用域名访问服务器只是在 IP 地址访问Web 服务器的基础上增加了域名解析
使用域名访问 Web 服务器
通过某种介质连接网络
在 DNS 解析可能会给出 CDN 服务器的 IP 地址
CDN 会缓存网站大部分资源
如四层的 LVS 或者七层的 Nginx
这个时候可能还有负载均衡设备
最后网站的响应数据原路返回到浏览器
真实网络环境中
Http请求的流程
一发一收的模式
工作流程
描述请求或响应的基本信息
请求行
在浏览器中叫 General
起始行(start line)
响应头(数据返回的时候才会有) Response Headers
请求头(发送的时候才会有) Requests Headers
头部字段集合(header)
使用 Key-Value 形式更详细地说明报文
又叫body
消息正文(entity)
报文结构
HTTP 协议规定报文必须有 header
可以没有 body
header 后面必须有一个\"空行\
协议规定
GET / HTTP/1.1
起始行
响应头
Host: www.baidu.comConnection: keep-alivePragma: no-cacheCache-Control: no-cachesec-ch-ua: \" Not A;Brand\";v=\"99\
请求头
消息正文
实际数据查看分析
请求方法
请求目标
表示报文使用的 HTTP 协议版本
版本号
结构
\"GET\" 是请求方法
\"/\" 表示请求目标
\"HTTP/1.1\"表示 HTTP 的版本号
示例
请求行(request line)
服务器响应的状态
出现在响应头
报文的 HTTP 版本号
状态码
原因
HTTP/1.1 200 OK
HTTP/1.1 404 Not Found
状态行(status line)
头部字段名不区分大小写
字段名里不允许出现\
字段名后面必须紧接着\":\
有的网站反爬会做字段名排序检查
字段顺序没有意义
头部字段
Date
在请求头和响应头里都可以出现的
通用字段
仅能在请求头中出现
请求字段
Server 非必要出现的字段
仅能出现在响应头中
响应字段
实体字段
常用头字段
头字段\":\
小问题
HTTP 报文
从服务器获取资源
GET
获取资源的元信息
HEAD
表示新建 \"Create\"的含义
数据放在报文的 body 里
POST
类似于 POST
UPDATE 的含义
PUT
常用方法
删除资源
DELETE
建利特殊的连接隧道
类似于代理IP 中的隧道代理
CONNECT
列出可对资源实行的方法
OPTIONS
追踪请求- 响应的传输路径
TRACE
非常用方法
MKCOL
COPY
MOVE
锁定资源暂时不允许修改
LOCK
删除锁
UNLOCK
PATCH
扩展方法
在HTTP协议里,所谓的安全,是指请求方法不会对服务器上的资源造成实质的修改,所以只有GET和HEAD是安全的,因为是只读操作。
安全
概念:多次执行相同的操作,结果也都是相同的
GET和HEAD 即是安全的也是幂等的
DELETE可以多次删除同一个资源,效果都是“资源不存在”,所以也是幂等
POST是新增或提交数据,多次提交会创建多个资源,所以不是幂等的
PUT是替换或更新数据,多次更新一个资源,资源还是第一次更新的状态。所以是幂等的
幂等
非幂等
安全与幂等
URI 全称叫统一资源标识符
URL 全称叫统一资源定位符
概念
scheme :// host:port path ?query
URI 的格式
资源应该用那种协议访问
scheme
作用是分隔 协议名 和后面部分
特定字符
://
通常以\"host:port\
不写端口号默认 80 或者 443
资源所在的主机名
authority
标记资源所在位置
采用了 unix 的风格
path 部分必须以\"/\
path
以\"?\
KV 值用字符\"&\"连接
http://www.chrono.com:8080/11-1?uid=1234&name=mario&referer=xxx
查询参数
query
主机名: Nginx.org
http://nginx.org
主机名: \"www.chrono.com\"
端口号: \"8080\"
路径: \"/11-1\"
http://www.chrono.com:8080/11-1
主机名: \"tools.ietf.org\"
端口号: 默认的\"443\"
路径: \"/html/rfc7230\"
https://tools.ietf.org/html/rfc7230
协议名:\"file\
\"://\" 分隔符
路径: \"/D:/http_study/www/\"
file:///D:/http_study/www/
协议名: \"http\"
主机名:\"www.chrono.com\"
端口号:\"8080\"
路径:\"/11-1\"
查询参数:\"name=mario&referer=xxx\"
例子
基本组成
URI 的完整格式
一、身份信息 \"user:passwd@\"
URI 所定位的资源内部的一个\"锚点\
浏览器可以在获取资源后直接跳转到它指示的位置
不会把 \"#fragment\" 发送给服务器
二、片段标识符 \"#fragment\"
完整格式和基本格式的区别
俗称转义
URI 中只能使 ASCII 码
escape(目前已被废除)
encodeURI
%20
空格
\"%3F\"
\"?\"
“%E9%93%B6%E6%B2%B3”
\"银河\"
URI 编码
为啥浏览器上看不到转义后的\"乱码\"
后记
RFC 标准里目前有 41 个错误码
具体的错误还是需要看错误信息的
\"101 Switching Protocols\"
101
1xx:
200 OK
要正确的和 200 区分
204 No Content
常用于分块下载或者断点续传
客户端发送\"范围请求\
206 Partial Content
2xx:
比如 HTTP 切换到 HTTPS
浏览器会存在缓存
301 Moved Permanently
不会做缓存优化
302 Found
类似 302
但要求重定向后的请求改为GET方法
避免POST/PUT重复操作
303 See Other
缓存重定向
用于缓存控制
可以理解成\"重定向已到缓存的文件\"
304 Not Modified
类似302
但重定向后请求里的方法和实体不允许变动,含义比302更明确
307 Temporary Redirect
类似307
不允许重定向后的请求变动,但它是301“永久重定向”的含义
308 Permanent Redirect
3xx:
服务端应尽量避免给客户端返回 400
400 Bad Request
服务器禁止访问资源
非客户端错误
403 Forbidden
资源在本服务器上未找到
404 Not Found
不允许使用某些方法操作资源
例如: 只能 GET 不允许 POST
405 Method Not Allowed
资源无法满足客户端请求的条件
例如: 请求中文但是只有英文
406 Not Acceptable
408 Request Timeout
多个请求发生了冲突
可以理解成多线程并发时的竞态
409 Conflict
请求报文里的 body 太大
413 Request Entity Too Large
请求行里的 URI 太大
414 Request-URI Too Long
客户端发送请求太多了
常见于服务器的限连策略
429 Too Many Requests
请求头某个字段或总体太大
431 Request Header Fields Too Large
4xx:
500 Internal Server Error
客户端请求的功能还不支持
501 Not Implemented
502 Bad Gateway
\"临时\"状态
响应报文里通常有个\"Retry-After\
503 Service Unavailable
5xx:
响应状态码
HTTP 协议是一个“灵活可扩展”的传输协议
灵活可扩展
HTTP 协议是一个“可靠”的传输协议。
\"可靠\
可靠传输
HTTP 协议是一个应用层的协议
应用层协议
HTTP 协议使用的是请求 - 应答通信模式
把 HTTP 请求处理封装成远程函数调用
WebService
RESTful
gRPC
产物
完全符合 RPC(Remote Procedure Call) 工作模式
请求-应答
HTTP 协议是无状态的
每个请求都是互相独立、毫无关联的,协议不要求客户端或服务器记录请求相关的信息。
\"无状态\"特点与响应头里的\"状态码\" 是两个概念
无状态
可分段获取数据
支持身份认证
支持国际化语言等
其它特点
HTTP 的特点
HTTP 最大的优点是简单、灵活和易于扩展;
允许开发者任意定制、扩充或解释
可以使用 TCP、UNIX Domain Socket、SSL/TLS、UDP、QUIC
不限制具体的下层协议
灵活和易于扩展:
简单、灵活、易于扩展
HTTP 拥有成熟的软硬件环境,应用的非常广泛,是互联网的基础设施
从简单的 web 页面到 json、XML 数据
从台式机浏览器上到 APP、新闻、论坛、游戏等等
天然具有\"跨语言、跨平台\
应用广泛、环境成熟
服务器不需要额外资源来记录状态信息
没有\"状态\
轻松实现高并发
优点
HTTP 是无状态的,可以轻松实现集群化,扩展性能,但有时也需要用 Cookie 技术来实现“有状态”;
服务器没有\"记忆能力\
HTTP 是明文传输,数据完全肉眼可见,能够方便地研究分析,但也容易被窃听
HTTP 报文的所有信息暴露
容易伪造
明文
HTTP 是不安全的,无法验证通信双方的身份,也不能判断报文是否被窜改;
缺少身份认证和完整性校验
HTTPS 解决了这一点
不安全
HTTP 的性能不算差,但不完全适应现在的互联网,还有很大的提升空间
关键在于\"请求-应答\"
现有解决方案: HTTP/2 和 HTTP/3
性能
缺点
HTTP 优缺点(HTTP/1.1)
MIME( Multipurpose Internet Mail Extensions) 多用途互联网邮件扩展
通常被叫做 MIME type
文本格式的可读数据
text
图像文件
image
音频和视频数据
audio/video
必须由上层应用程序来解释
application/json,application/javascript、application/pdf
application
gzip
deflate
一种专门为 HTTP 优化的新压缩算法 (Brotli)
br
压缩
数据类型与编码
请求头中
作用: 标记客户端可理解的 MIME type
可以用 \
Accept
标记客户端支持的压缩格式
Accept-Encoding
响应头中
Content-Type: text/htmlContent-Type: image/png
Content-Type
标记服务器返回的数据压缩格式
只能选择客户端传过来的其中一种
Content-Encoding: gzip
Content-Encoding
数据类型使用的头字段
语言类型与编码
用于客户端和服务器语言与编码\"内容协商\"
标记客户端可理解的自然语言
允许用\
Accept-Language
字符集在 HTTP 里的使用字段
Accept-Charset
告诉客户端实体数据使用的实际语言类型
Content-Language: zh-CN
Content-Language
在响应头里包含了 body 的编码格式
响应头里
Content-Type: text/html; charset=utf-8
请求头中一般只会有 Accept-Language 字段
Content-Type: text/html; charset=utf-8
响应头里一般只会有 Content-Type 字段
语言类型使用的头字段
q=quality factor
在数据类型或语言代码后加\";\"分隔
在 HTTP 里\
响应报文的特殊的\"版本标记\"
Vary
内容协商质量值
HTTP 的实体数据
请求头中添加 Accept-Encoding 字段
支持 gzip、deflate、br
缺点: gzip 等压缩算法通常只对文本文件有较好的压缩率
数据压缩
\"chunked\"分块传输编码
表示 body 数据的长度未知
响应头中用字段 \"Transfer-Encoding: chunked\" 来表示
表示 body 里数据长度是已知的
Content-Length
在响应头中 \"Transfer-Encoding: chunked\" 和 \"Content-Length\" 是互斥的
具体规则
分块传输的编码规则
分块传输
由客户端发送请求
Range: bytes=x-y
假设文件是 100 字节
\"0-\"表示从起点到文档终点
\"10-\"表示从第 10 个字节开始到文档末尾
\"-1\"表示文档的最后一个字节
\"-10\
越界返回状态码 416
Range: bytes=0-31
返回状态码 206 Partial Content
格式 bytes x-y/length
Content-Length: 32Accept-Ranges: bytesContent-Range: bytes 0-31/96
服务器收到 Range 字段后的四件事
请求头中使用 Range 字段
Accept-Ranges:bytes
Accept-Ranges:none
返回范围请求的具体长度
Content-Length: 146515
响应头中返回两个字段
断点续传也是基于范围请求来实现的
断点续传的要点
范围请求
在 Range 头里使用多个\"x-y\
表示报文的 body 是由多段字节序列组成
还需要一个参数\"boundary=xxx\"给出段之间的分隔标记
需要使用热书的 MIME 类型: \"multipart/byteranges\"
请求
这里的\"--00000000001\"是多段分隔符
HTTP/1.1 206 Partial ContentContent-Type: multipart/byteranges; boundary=00000000001Content-Length: 189Connection: keep-aliveAccept-Ranges: bytes--00000000001Content-Type: text/plainContent-Range: bytes 0-9/96// this is--00000000001Content-Type: text/plainContent-Range: bytes 20-29/96ext json d--00000000001--
响应
多段数据
HTTP 传输大文件的方法
服务器端通常不会主动关闭连接
常见于 HTTP/1.0 及以前
又叫做\"无连接\"
缺点: 在需要多次请求的场景中非常的耗时
短连接
为了解决\"短连接\
又叫\"持久连接(persistent connections)\"、\"连接保活(keep alive)\"、\"连接复用(connection reuse)\"
常见于 HTTP/1.1 及以后版本
缺点: \"长\
在请求头里加上\"Connection:close\
使用\"keepalive_timeout\
使用\"keepalive_requests\
使用 \"keepalive_timeout 60\" 和 \"keepalive_requests 5\
Nginx 中
解决办法:
长连接
长连接和短连接的比较
也可以使用 Connection: keep-alive
断开可以在最后一个请求头中添加\"Connection:close\"字段
请求头中添加\"Connection:keep-alive\"字段
断开可以在最后一个请求头中添加\"Connection:close\"字段
HTTP/1.0 及以下
连接相关的头字段
Head-of-line blocking 也叫\"队首阻塞\"
由 HTTP 的\"请求-应答\" 模型所致
因为 HTTP 规定报文必须是\"一发一收\
原因:
队头阻塞
目前浏览器中使用 6-8 个连接
并发连接
还是用数量来解决质量的思路
域名分片
性能优化
HTTP 的连接管理
如: 点击网页上的一个超链接
主动跳转
HTTP 协议里叫做\"重定向\"(Redirection)
被动跳转
跳转
请求返回状态码 302/301
只有配合 \"302/301\"状态码才有意义
标记了服务器要求重定向的 URI
既可以是绝对路径
只能在站内跳转使用
也可以是相对路径
响应头里面标记了\"Location: URI\"
重定向的过程
站外重定向
站内重定向和站外重定向的区别
永久重定向
301
临时重定向
302
避免 POST/PUT 重复操作
303
含义比 302 更明确
307
是 301 的含义
308
重定向状态码
最常用的
域名变更
服务器变更
网站改版
系统维护
让多个域名重定向到主站
避免重复
在决定要用重定向后一定要考虑是用 301 还是 302
应用场景
重定向机制会有多次\"请求-应答\"
性能损耗
循环跳转
重定向的相关问题
重定向
HTTP 的重定向和跳转
Cookies 的作用
用于服务器给浏览器发送身份标识
可以多行
响应头字段 Set-Cookie
用于身份甄别
多个字段使用\";\"分隔
请求头字段 Cookie
Cookies 的工作过程
作用:防止外泄或窃取
设置字段
过期时间
Expires
Max-Age
浏览器优先采用 Max-Age 计算失效期
设置 Cookie 的生存周期
从 URI 中提取 host
Domain
Path
Cookie: JSESSIONID=rVLCnVAjcFkkxgECAKHyUOqSPHM0l41ji9iOXxm93QowaTs7MgKg!-2091789827;domain=search.baidu.com; path=/; HttpOnly
设置 Cookie 的作用域
为了不让服务器以外的人看到
浏览器 JS 会禁用 document.Cookie 的一切相关 API
HttpOnly
可以防范\"跨站请求伪造\"(SXRF)攻击
SameSite=Strict
禁止 POST 跨站发送
SameSite=Lax
SameSite
浏览器中 Cookie 还是明文的
Secure
Cookie 的安全性
方法:
chrome -> F12 -> Network -> Cookies
浏览器中查看方法
Cookie 的属性
状态保持
身份识别
广告跟踪
Cookie 的应用
Cookie 不属于 HTTP 标准
RFC2616/7230 是 HTTP 标准
HTTP 的 Cookie
需要缓存的原因
响应头字段 cache-control:max-age=30
流程
浏览器只能缓存当前页面 31536000 秒
标记资源有效期
max-age “生存时间”
Cache-Control: max-age=31536000
不允许缓存
no-store
可以缓存,但使用之间必须去服务器验证是否过期,是否有新版本
no-cache
缓存不过期可以继续使用
过期了还想用必须去服务器验证
must-revalidate
响应头字段
服务器的缓存控制
如果浏览器不想使用缓存,而是想请求最新的资源
意思是请求一个最新资源
在请求头添加“Cache-Control:max-age=0”或者“no-cache”
这个头字段只支持 HTTP/1.0
在 HTTP/1.0 中,使用 \"Pragme: no-cache\" 效果和 Cache-Control 一致
windows:Ctrl+F5
Mac:cmd+shift+r
其实就是发送了一个“Cache-Control:no-cache”
强制刷新:
当在 Starts Code 字段发现有“from disk cache”,表明这个资源是缓存资源
客户端的缓存控制
如果验证资源是否失效,发送多个验证比较消耗资源
这个在head里增加“条件请求”字段,专门用来验证资源是否过期,把多个请求合并成一个,降低资源消耗
只能用在 GET 和 HEAD 请求中
当前资源过了有效期,需要修改才用
如果资源已经发生了改变,返回状态码 200,并更新缓存
如果资源没有发生改变,返回 304,并更新资源有效期
与 If-None-Match 一起出现时,会被忽略掉,除非服务器不支持 If-None-Match
if-Modified-Since
当服务器上没有任何资源的 ETag 属性值与当前资源匹配时,服务器返回所请求资源,响应码为 200
GET 和 HEAD 请求验证失败时,服务器必须返回 304
意思是发送一个请求,去服务段验证资源是否发生变化,如果资源发生了变化,ETag 肯定对不上,这个时候服务器返回请求资源,返回状态码 200
当 ETag 对上了,表示资源没有发生变化,然后服务器返回 304,更新资源过期时间
如果使用了弱 ETag,那么两个人间仅仅在页脚的生成时间有所不同,那也可以认为二者是相同的
if-None-Match
只有当资源在过期时间之后没有进行修改的情况下,服务器才会返回请求的资源,或者接受 POST 等方法的请求
如果在过期时间之后发生了改变,返回 412
If-Unmodified-Since
GET 和 HEAD 下,服务器仅在请求的资源满足 ETag 值时才会返回资源
对于 PUT 或其它非安全方法,只有在满足条件的情况下才可以讲资源上传
PUT 方法用这个参数可以避免更新丢失问题
If-Match
当字段值中的条件满足时,range 头字段才会起作用,同时服务器回复 206 部分状态码,以及 range 字段请求的相应部分
如果字段值条件不满足,返回 200 状态码,并返回完整的请求资源
If-Range
文件的最后修改时间
Last-modified
资源唯一标识
有强弱之分
弱 ETag 在值前有个 “W/”标记
强 ETag 必须完全一致
ETag
使用字段
请求流程
条件请求
HTTP 的缓存控制
正常的 HTTP 模型通信只有两个角色,一个是“请求方”浏览器,另一个是“应答方”服务器
起点:客户端,浏览器
中间:代理服务器(proxy server)
终点:源服务器(origin server)
在引入了代理之后,HTTP 模型成了三个角色的
服务本身不生成内容,而是处于中间位置转发上下游的请求和响应,具有双重身份
面对用户,表现为服务器
面对服务器,表现为客户
代理服务
欺上瞒下
即可以保护客户端,又可以保护服务端
有多台服务器时,只需要请求负载均衡服务器,然后由负载均衡服务器决定由哪台服务器来响应请求
负载均衡算法,如轮询,一致性哈希等
使用“心跳”等机制监控后端服务器,发现有故障就及时“踢出”集群,保证服务高可用
健康检查
保护被代理的后端服务器,限制 IP 地址或流量,抵御网络攻击和过载
对外网使用 SSL/TLS 加密通信认证,而在安全的内网不加密,消除加解密成本
加密卸载
拦截上下行的数据,任意指定策略修改请求或响应
数据过滤
暂存、复用服务器响应
功能
代理的作用
标明代理身份
只是解决了客户端和源服务器判断是否存在代理的问题,不能知道对方的真实信息
Via:proxy1,proxy2
如果有多个代理服务器,那么请求经过多少个代理服务器,Via 字段后面会追加多少个代理标识
有时候响应头里会使用“X-Via”,意义和 Via 相同
Via
不属于 HTTP 标准,但是属于“事实标准”
意思是为谁转发
添加的是请求方的 IP 地址,最左边的 IP 就是源请求方的 IP 地址
X-Forwarded-For
另一种获取客户端真是 IP 的手段
作用:只记录客户端的 IP 地址,没有中间的代理信息
X-Real-IP
RFC7239 定义了字段“Forwarded”代替 X-Forwarded-For 和 X-Real-IP,但是应用的不多
代理相关头字段
因为 X-Forwarded-For 等头字段需要修改原始报文,在有些情况下是不允许甚至不可能被修改的,比如使用了 HTTPS 通信被加密
所以出现了专门的“代理协议”
属于“事实协议”
HAProxy 所定义
V2 是二进制格式
有两个版本 V1 和 V2
V1 是明文,只是在 HTTP 报文前增加了一行 ASCII 码文本,相当于又多了一个头
开头必须是“PROXY”五个大写字母
然后是“TCP4”或者“TCP6”表示客户端的 IP 地址类型
之后是请求方地址、应答方地址、请求方端口号、应答方端口号,最后用回车换行符(\\)结束
格式
PROXY TCP 192.168.12.108 192.168.12.105 5555 8080\\GET / HTTP/1.1\\Host:www.xxx.com\\\\
V1
代理协议不支持 X-Forwarde-For 的链式地址形式
代理协议
HTTP 的代理服务
支持缓存控制的代理服务
作用:减少响应时间,节约带宽,提升客户端的用户体验
服务端缓存适用于“读多写少”的数据
HTTP 的服务器缓存功能主要由代理服务器来实现
既是客户端,又是服务端
即不是客户端,又不是服务端
浏览器通过缓存代理服务器向源服务器发送请求,源服务器收到请求后原路返回,在原路返回过程中,缓存代理服务器保留一份报文到缓存,然后返回给浏览器
之后的所有相同的请求,都会由缓存代理返回报文
属于数据中转站
缓存代理服务
在响应头字段增加属性
需要区分客户端缓存和代理缓存
只能在客户端保存,不能放在代理上
禁止代理缓存,客户端缓存有效期 5 秒
private
缓存完全开放,谁都可以存,谁都可以用
代理上缓存有效期 10 秒,客户端有效期 5 秒
public
Cache-Control 新属性
过期就必须回源服务器验证
代理的缓存过期后必须验证,客户端不必回源
只验证到代理这个环节
proxy-revalidate
只限定在代理上能够存多久
客户端仍然使用 max-age
s-maxage
代理专用的属性
禁止代理对缓存下来的数据做一些优化
比如:把图片生成 png、webp 等几种格式
no-transform
客户端、代理上缓存有效期都是 30 秒,代理缓存过期后去源服务器更新,并且禁止对缓存文件优化
Last-modified 新属性
源服务器的缓存控制
请求头处理
允许代理上的缓存过期的最大时间内可用
过期 3 秒也能接受
max-stale
缓存必须有效,而且必须在 x 秒后依然有效
在缓存有效期内,在 1 秒后还有效才可以成功
如果响应头 max-age=10,过了 5 秒,请求是请求头上 “min-fresh=1”,5+1<10,就还能发出去
min-fresh
内容协商的结果
报文版本标记
同一个请求,经过内容协商后可能会有不同的字符集、编码、浏览器等版本
当收到同一个请求,代理就读取缓存里的 Vary,对比请求头里的所有字段
当用了 Vary,要求当前请求和上一个请求得完全匹配,包括压缩,user-agent,Accept-Encoding 等都得一致
Vary
缓存清理
对代理非常重要
过期数据及时淘汰,避免占用空间
源站资源更新,需要删除旧版本,主动换成新版本
缓存了一些本不该存储的信息,及时删除,如:网络谣言,危险连接等
作法:使用自定义请求方法“PURGE”,发送给代理服务器,要求删除 URI 对应的缓存数据
Purge
其它问题
HTTP 的缓存代理
因为 HTTP 不安全
HTTP 任何人都能截获、修改、伪造请求、响应报文等,数据不具有可信性
为啥要有 HTTPS
拥有以下四个特性可以被认为是安全的
对数据的“保密”
只能由可信的人访问,对其他人是不可见的
机密性(Secrecy/Confidentiality)
也叫一致性
指在传输过程中没有被篡改,“完完整整”的保持着原样
完整性(Inegrity)
确认对方的真是身份
保证消息只能发送给可信的人
身份认证(Authentication)
也叫不可抵赖
不能否认已经发生过的行为
收到了就是收到了,没收到就是没收到
防止耍赖皮
不可否认(Non-repudiation/Undeniable)
怎样通信过程才会安全
解决了安全通信的大部分问题
解决的了通信事务的真实性
是一个“非常简单”的协议
RFC 文档很小,只有 7 页
新协议名“HTTPS”,默认端口号 443
其它沿用 HTTP
由“HTTP over TCP/IP”变成了“HTTP over SSL/TLS”
收发报文不再使用 Socket API 而是调用专门的安全接口
什么是 HTTPS
SSL 安全套接层(Secure Sockets Layer)
在 OSI 模型中的第 5 层(会话层)
由网景公司于 1994 年发明
有 V2 和 V3 两个版本,V1 有缺陷所以从未公开
1999 年由互联网工程组 IETF 改名为 TLS(传输层安全,Transport Layer Security)从此正式成为标准化,版本号从 1.0 重新算起
TLS1.0 实际上就是 SSLv3.1
已经被认定为不安全的
各大浏览器将在 2020 年左右停止支持
1.1 2006 年发布
目前最广泛的版本
1.2 2008 年发布
1.3 2018 年发布
TLS 版本
记录协议
握手协议
警告协议
变更密码规范协议
扩展协议等几个自协议组成
TLS 的构成
浏览器与服务器使用 TLS 建立连接时会选择一组恰当的加密算法来实现安全通信
多个加密算法,最后协定使用 ECDHE-RSA-AES256-GCM-SHA384
秘钥交换算法+签名算法+对称加密算法+摘要算法
ECDHE-RSA-AES256-GCM-SHA384
握手时使用 ECDHE 算法进行秘钥交换,用 RSA 签名和身份认证,握手后的通信用 AES 对称算法,秘钥长度 256,分组模式是 GCM,摘要算法 SHA384 用于消息认证和产生随机数
命名规范,固定格式:
SSL/TLS
著名的开源密码学程序库和工具包
几乎支持所有公开的加密算法和协议,已经成为了事实标准
是 SSL/TLS 的具体实现
1.02
1.1.0
最新
1.1.1
版本分支
2019 年年底不再维护
OpenSSL
HTTPS,SSL/TLS
作用:实现 TLS 的机密性
加密和解密使用同一个密钥
只要保证了秘钥的安全,整个通信过程就具有了机密性
RC4
DES
3DES
解释:高级加密标准(Advanced Encryption Standard)
128
192
256
密钥长度
安全强度很高,性能好,有的硬件会做特殊优化
DES 算法的替代者,应用最广泛的对称加密算法
AES
Google 设计的
固定为 256
纯软件运行性能超过 AES
以前在移动客户端上比较流行,后来 ARMv8 加入了 AES 硬件优化,不再具有明显优势
ChaCha20
类型
不安全,通常禁止使用
效率高,安全性差
对称加密
作用:可以让算法用固定长度的密钥加密任意长度的明文
ECB
CBC
CFB
OFB
最新的分组模式(Authenticated Encryption with Associated Data)
加密的同时增加了认证功能
AEAD
密钥长度 128 位,分组模式是 GCM
AES128-GCM
GCM
CCM
ChaCha20 算法,使用分组模式Poly1305
ChaCha20-Poly1305
Poly1305
以前的分组模式,现在都不怎么用了,被发现有安全漏洞
加密分组模式
原理:生成两个密钥,一个公钥(public key)一个私钥(private key)两个密钥不相同,公钥可以公开给任何人用,私钥必须严格保密
DH
DSA
安全性基于“整数分解”的数学难题,使用两个超大素数的乘积作为生成密钥的材料
推算私钥非常困难
10 年前推荐 RSA 密钥长度为 1024 位,现在普遍认为至少需要 2048 位
RSA
基于“椭圆曲线离散对数”,使用特定曲线方程和基点生成公私钥
子算法 ECDHE 用于密钥交换,ECDSA 用于数字签名
160 位的 ECC 相当于 1024 位的 RSA,224 位的 ECC 相当于 2048 位 RSA
因为密钥短,加密时间和计算量,消耗的内存,带宽少,加密解密性能上去了,安全性也高
ECC
安全性高,效率差
非对称加密
混合加密就是把对称加密和非对称加密混合起来使用
TLS 中使用的就是混合加密
非对称加密解决密钥交换问题(这里交换的是对称加密密钥)
会话密钥就是对称加密密钥
然后用随机数产生对称算法使用的“会话密钥”(session key)再用公钥加密
对方拿到密钥后用私钥解密,取出会话密钥,双方实现了对称密钥的安全交换
之后不再使用非对称加密
混合加密
对称加密与非对称加密
作用:完整性,身份认证
实现完整性的主要手段
通常是散列函数、哈希函数(Hash Function)
16 字节摘要
MD5
20 字节摘要
SHA-1
常用的
安全强度比较低,TLS 里禁止使用
TLS 推荐使用 SHA-2
28 字节摘要
SHA224
32 字节摘要
SHA256
48 字节摘要
SHA384
SHA-2 系列
摘要算法不具备机密性,如果明文传输也会被一起修改,所以要配合混合加密
摘要算法
只要在原文后附上它的照耀,就能保证数据的完整性
就算输入极其相似的数据,在摘要算法的结果上也会产生非常大的变化
网站收到数据后,通过计算摘要,然后和附带的摘要对比,就能知道数据是否发生修改,来确保数据的完整可信
完整性必须建立在机密性之上
在混合加密系统里用会话密钥加密消息和摘要
术语:哈希消息认证码(HMAC)
完整性
作用:确认身份,防止被骗
加密算法结合摘要算法,通信过程是保密了,但是通信的两端,客户端和服务端到现在是还没有说怎么来确定他是客户或者是服务器而不是非法窃取你机密的人
数字签名就是用来确定客户端和服务端的身份
方法:把公钥和私钥反过来,私钥加密,公钥解密
签名
私钥通过对 SHA-2 加密
验签
这里的公私钥服务器和客户端都有
拿到文件之后通过公钥解密,拿到 SHA-2 之后和原文的 SHA-2 对比
专业术语叫“签名”和“验签”
过程
客户端用自己的私钥签名一个消息
网站收到后用客户端的公钥验签
确认身份之后,用服务端的私钥签名一个消息
客户端收到后用服务端的公钥进行验签
之后就可以用混合加密进行安全通信了
数字签名
解决“公钥的信任”问题
作用:避免公钥被伪造
不适用类似于密钥交换的方法来解决公钥认证问题,是为了避免套娃
(Certificate Authority 证书认证机构) 用自身信誉来保证公钥无法伪造,必须是具有极高可信度的
CA 对公钥签名认证是有格式的
包含了序列号、用途、颁发者、有效时间等,打包再签名形成了“数字证书”
DigiCert
VeriSign
Entrust
Let's Encrypt等
证书办法机构
可信度最低,只对域名可信
不能证明网站拥有者身份
DV
OV
可信度最高,进过了法律和审计的严格核查
可以证明网站拥有者的身份
EV
证书类型
大 CA 给小 CA 签名认证
最终 Root CA 自己证明自己(自签证书(Self-Signed Certificate)/根证书(Root Certificate))
证书链
CA 如何证明自己
操作系统和浏览器内置了各大 CA 的根证书
当服务器发过来它的证书的时候,验证证书里的签名,顺着证书链验证,直到找到根证书,才能确定证书是可信的
证书的验证
CA
CA 被欺骗或者失误,造成错发证书
2011 年荷兰 CA DigiNotar 被黑客攻陷,颁发了 531 个伪造 CA
CA 被黑客攻陷
CA 有恶意
面对前面两个,失误或者被黑客攻陷,开发出了 CRL(证书吊销列表,Certificate revocation list)和 OCSP(在线证书状态协议,Online Certificate Status Protocol),及时废止有问题的证书
面对恶意 CA,因为设计太多证书,所以只能从操作系统或者浏览器上删除“根证书”
解决办法
证书体系的弱点
数字证书和 CA
数字签名与证书
TLS1.2 诞生于 2008 年
TLS 会进行类似于 TCP 一样的握手
HTTPS 建立连接
规定了 TLS 收发数据的基本单位,记录(record)
类似于 TCP 的 segment
记录协议(Record Protocol)
向对方发出警报信息
像 HTTP 协议里的状态码
Protocol_version 就是不支持旧版本
bad_certificate 就是证书有问题
收到报警后另一方可以选择继续,也可以终止连接
警报协议(Alert Protocol)
TLS 里最复杂的子协议
比 TCP 的 SYN/ACK 复杂
浏览器和服务器需要通过握手协商 TLS 版本,随机数,密码套件等信息
然后交换证书和密钥参数,最终双方协商得到会话密钥
握手协议(Handshake Protocol)
通知对方,后续数据都将使用加密保护
在它之前,所有数据都是明文的
变更密码规范协议(Change Cipher Spec Protocol)
TLS 协议的组成
TCP 建立连接之后
用于生成后续会话密钥
Handshake Protocol: Client Hello Version: TLS 1.2 (0x0303) Random: 1cbf803321fd2623408dfe… Cipher Suites (17 suites) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
1、Client -> Server :发送一个 Client Hello 消息,里面包含了(客户端的版本号、支持的密码套件、一个随机数(Client Random))
密码套件:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
作用就是对一下版本号和选一个密码套件,然后给一个随机数,用于加密解密
Handshake Protocol: Server Hello Version: TLS 1.2 (0x0303) Random: 0e6320f21bae50842e96… Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
2、Server -> Client:服务器收到 Client Hello 后,返回一个 Server Hello 消息,包含了(随机数,确认 TLS 版本号,从客户端的列表里选一个通信密码套件)
证明自己的身份
3、Server -> Client:服务器把证书发送给客户端(Server Certificate)
实现密钥交换算法,再加上自己的私钥签名认证
这里使用椭圆曲线生成公钥是因为这里的前面交换的信息中使用的密码套件是 ECDHE 的他用的是椭圆曲线生成公钥
Handshake Protocol: Server Key Exchange EC Diffie-Hellman Server Params Curve Type: named_curve (0x03) Named Curve: x25519 (0x001d) Pubkey: 3b39deaf00217894e... Signature Algorithm: rsa_pkcs1_sha512 (0x0601) Signature: 37141adac38ea4...
4、Server -> Client:服务器在证书发送后发送“Server Key Exchange”消息,包含了 椭圆曲线的公钥(Server Params)
这里,客户端拿到了 Client Random,Server Random 和 Server Params,还有服务器的证书
Server Params 是服务器的公钥
5、Server -> Client:服务器再发送一个“Server Hello Done”消息,告诉客户端,我的信息发送完了
确认服务器身份
这里的证书是加密了公钥的
6、客户端开始走证书链逐级验证证书,确认证书的真实性,再用证书公钥验证签名
交换密钥算法参数
服务器拿到了客户端的公钥
Handshake Protocol: Client Key Exchange EC Diffie-Hellman Client Params Pubkey: 8c674d0e08dc27b5eaa…
7、Client -> Server :客户端按照密码套件要求,也生成一个椭圆曲线的公钥(Client Params),用“Client key Exchange”消息发给服务器
客户端和服务端都拿到了 双方的公钥,通过 ECDHE 算法计算出一个随机数,这个随机数被称为“Pre-Master”
计算出主密钥 Master Secret
主密钥不是会话密钥
还会再用 PRF 扩展出更多的密钥,比如客户端发送用的会话密钥(client_write_key)、服务器发送用的会话密钥(server_write_key)
PRF 基于密码套件里的最后一个参数进强化
因为不信任客户端或服务器伪随机书的可靠性
为了保证真正的“完全随机”“不可预测”
为了随机程度高,不让黑客容易猜到
为什么非要三个随机数
然后用 PRF 伪随机函数把 Client Random、Server Random 和 Pre-Master 通过密码套件的摘要算法再次强化,得到结果值 master secert 的随机性
为了避免只用一个密钥带来的安全隐患
8、Client -> Server :生成主密钥和派生的会话密钥,客户端发一个“Change Cipher Spec” 告诉服务器,之后所有的消息都改用商定好的对称加密通信
9、Client -> Server :客户端再发送一个“Finished”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器验证
10、Server -> Client:服务器也重复了 8,9 的操作
11、双方都验证加密解密 ok,握手正式结束
ECDHE 握手过程
随机数 C,客户端的 TLS 版本号,密码套件列表,扩展列表
1、客户端向服务端发送 Client Hello
随机数 S,确认 TLS 版本号和使用的密码套件(RSA)
2、服务端向客户端发送 Server Hello
服务器使用的证书
3、服务端向客户端发送 Server Certificate
服务器 Hello 完成
4、server -> client Server Hello Done
通过证书链
5、client 验证证书
服务端 RSA 公钥加密 Pre-Master
这里的 Pre-Master 是一个客户端生成的随机数,没有用算法生成
密钥交换
6、client->server Client Key Exchange
7、server 用私钥解密 Pre-Master
这里的 “随机数c/s” 的意思是 client 随机数和 server 随机数
8、client,server 用 随机数 C/S 加 Pre-Master 算出主密钥 master secret
告诉服务器,之后改用会话密钥加密通信
9、client -> server Change Cipher Spec
发送所有握手数据的摘要,让 server 端校验
10、client->server Finished
告诉 client,之后所有会话机密通信
11、server -> client Change Cipher Spec
所有握手数据的摘要,让客户端校验
12、server-> client Finished
握手结束
RSA 握手过程
上面的都是单向认证,只认证了服务器的身份,没有认证客户端的身份
只是在“Server Hello Done” 之后 “Client Key Exchange”之前,客户端要发送 “Client Certificate”消息
服务器收到后也把证书链走一遍,验证客户端的身份
区别
双向认证
HTTPS 协议会闲鱼服务器执行 TCP 握手,然后执行 TLS 握手,才能建立安全连接
握手的目标是安全的交换对称密钥,需要三个随机数,第三个随机数“Pre-Master”必须加密传输,绝对不能让黑客破解
“Hello”消息交换随机数,“Key Exchange”消息交换“Pre-Master”
“Change Cipher Spec” 之前传输的都是明文,之后都是对称密钥加密的秘闻
要点
第一阶段,交换随机数
第二阶段,证书验证
第三阶段,主密钥生成
流程总结
TLS1.2连接过程解析
TLS1.3 诞生于 2018 年
诞生原因,TLS1.2 在安全,性能方面跟不上互联网的发展速度了
改进目标:兼容、安全、性能
0x303
TLS1.2
0x304
TLS1.3
TLS1.2 和 TLS1.3 的区分方法
因为 TLS1.1,1.2 协议出现了很多年,很多的软件,中间代理等只认老的记录协议格式
更新改造很困难,
一旦变更了记录头字段里的版本号,大量的代理服务器,网关都将无法正常处理,TLS 握手失败
为了老设备能够继续使用,避免新协议带来的冲击
为啥要兼容
类似于补充条款
扩展协议(Extension Protocol)
用于区分新旧版本
握手 Hello 消息后面添加 supported_versions
如果服务器不支持 1.3,那就“向后兼容”降级成为 1.2
支持的曲线
supported_groups
曲线对应的参数
key_share
signature_algorithms
server_name
Handshake Protocol: Client Hello Version: TLS 1.2 (0x0303) Extension: supported_versions (len=11) Supported Version: TLS 1.3 (0x0304) Supported Version: TLS 1.2 (0x0303)
兼容方法
扩展的方法
最大化兼容性
伪随机函数由 PRF 升级为 HKDF(HMAC-based Extract-and-Expand Key Derivation Function)
明确禁止在记录协议里使用压缩
废除 RC4、DES 对称加密算法
废除 ECB、CBC 等传统分组模式
废除 MD5、SHA1、SHA-224 摘要算法
如果有黑客长期收集混合加密系统收发的所有报文,如果系统使用服务器证书里的 RSA 做密钥交换,一旦私钥泄漏或破解,黑客能够使用私钥解密出之前所有报文的“Pre-Master”,再算出会话密钥,破解所有密文
废除原因,不具有“前向安全”
废除 RSA、DH 密钥交换算法和许多命名曲线
只保留了 AES、ChaCha20 对称加密算法
分组模式只能用 AEAD 的 GCM、CCM 和 Poly1305
摘要算法只能用 SHA256、SHA384
每次握手时都会生成一对临时公钥和私钥,即“一次一密”
每次通信的密钥对都是不同的
密钥交换算法只有 ECDHE 和 DHE
椭圆曲线只剩 P-256 和 X25519等 5 种
TLS1.3 只有 5 个套件
密码套件
强化安全
TLS 握手时减少了几个步骤
压缩了以前 Hello 协商过程
删除了“Key Exchange”消息
Client Hello 消息里用 “supported_groups”带上支持的曲线
“key_share”带上曲线对应的客户端公钥参数
用“signature_algorithms”带上签名算法
服务器收到后再扩展里选定一个曲线和参数,再用“key_share”扩展返回服务器公钥参数,实现了双方密钥交换
用 pre_shared_key 和 early_data 扩展
做法:
提升性能
随机数 C、密码套件、密钥交换算法参数(key_share)
Handshake Protocol: Client Hello Version: TLS 1.2 (0x0303) Random: cebeb6c05403654d66c2329… Cipher Suites (18 suites) Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301) Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303) Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Extension: supported_versions (len=9) Supported Version: TLS 1.3 (0x0304) Supported Version: TLS 1.2 (0x0303) Extension: supported_groups (len=14) Supported Groups (6 groups) Supported Group: x25519 (0x001d) Supported Group: secp256r1 (0x0017) Extension: key_share (len=107) Key Share extension Client Key Share Length: 105 Key Share Entry: Group: x25519 Key Share Entry: Group: secp256r1
表示这是 TLS1.3
supported_versions
表示支持哪些曲线
表示曲线对应的参数
1、Client -> Server :Client Hello
随机数 S、确认密码套件、交换算法参数(key_share)
确认使用 TLS版本号
带上曲线和对应公钥参数
2、Server -> Client:Server Hello
Client Random
Server Random
Client Params
Server Params
以上两条消息,客户端和服务端就共享了四个信息:
3、Server 用各自的 ECDHE 算出“Pre-Master”,再用 HKDF 生成主密钥“Master Secret”
告诉Client,之后都用会话密钥加密通信
比 TLS1.2 提早进入加密通信,后面的证书等都是加密的,减少握手时明文信息泄漏
4、Server -> Client:Change Cipher Spec
被加密的扩展信息
5、Server -> Client:Encrypted Extensions
6、Server -> Client:Server Certificate
使用证书签名握手数据
用服务器私钥把前面的曲线、套件、参数等握手数据加了签名,作用和“Finished”差不多
由于是私钥签名,强化了身份认证和防篡改
7、Server -> Client:Server Certificate Verify
所有握手数据的摘要
8、Server -> Client:Finished
9、Client 开始验证证书和签名,然后 ECDHE 计算 Per-Master,再用 HKDF 生成主密钥“Master Secret”
10、Client -> Server :Change Cipher Spec
11、Client -> Server :Finished
图示
握手分析
TLS1.3 特性解析
第一建立连接时的非对称加密握手
第二是握手后的对称加密报文传输
HTTPS 比 HTTP 增加了一个 TLS 握手步骤,这个步骤最长多花 2-RTT
ECDHE 生成用于密钥交换的临时公钥对
验证证书时访问 CA 获取 CRL 或者 OCSP
非对称加密解密处理“Pre-Master”等
握手消息网络耗时之外还有其它消耗
慢的原因
所以,网卡,带宽,SSD 存储没有优化作用
HTTPS 连接是计算密集型
想要快,就要选更快的 CPU,最好内建 AES 优化,可以加速握手,加速传输
加解密时调用它的 API
让专门的硬件来做非对称加解密,分担 CPU 的计算压力
缺点:升级慢、支持算法有限
SSL 加速卡
专门的服务器集群来“卸载”TLS 握手时的加解密计算
SSL 加速服务器
硬件优化
Linux 内核由 2.x 升级到 4.x
Nginx 由 1.6 升级到 1.16
OpenSSL 由 1.0.1 升级到 1.1.0/1.1.1
将软件尽量升级到最新版本
软件升级
最容易的方法
软件优化
TLS升级,最好升级到 TLS1.3
TLS1.3 完全握手只要 1-RTT,而且更加安全
能够把握手消息往返由 2-RTT 减少到 1-RTT
运算快,安全性高
支持“False Start”
只能用 1.2时,握手时使用的密钥交换协议尽量用椭圆曲线的 ECHDE 算法
使用椭圆曲线选择高性能曲线,最好是 x25519,次优选择P-256
比 AES_256_GCM 略快一点
AES_128_GCM
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:EECDH+CHACHA20;ssl_ecdh_curve X25519:P-256;
Nginx 中可以用“ssl_ciphers”“ssl_ecdh_curve”等指令配置服务器使用的密码套件和椭圆曲线,把优先使用的放在前面
协议优化
证书传输
证书验证
优化点
224 位的 ECC 相当于 2048 位的 RSA,所以椭圆曲线证书比 RSA 证书小很多
能够节省宽带
服务器的证书可以选择椭圆曲线(ECDSA)证书而不是 RSA 证书
由 CA 定期发布
所有被撤销信任的证书序列号
只查这个列表就可以知道证书是否有效
不太常用
被 OCSP 替代
失效证书查询 CRL(Certificate revocation list,证书吊销列表)
OCSP(在线证书状态协议 Online Certificate Status Protocol),向 CA 发送查询请求,让 CA 返回证书的有效状态
让服务器预先访问 CA 获取 OCSP 响应,然后在握手时随证书一期发送给客户端,免去了客户端连接 CA 服务器查询的时间
使用 OCSP Stapling (OCSP 装订)
证书优化
不用了
和 HTTP Cache 一样
TLS session resumption
Server 和 Client 首次连接之后各自保存一个会话 ID
内存里存储主密钥和其他相关信息
当 Client 再次连接时发 ID 过来,服务器直接在内存找,找到了直接用主密钥恢复会话状态,跳过证书验证和密钥交换
只用一个消息往返就可以建立安全通信
Session ID (会话 ID)
服务器得保存每一个客户端的会话数据,客户端太多对服务器是一种压力,百万级,千万级用户存储量会成问题
Handshake Protocol: Client Hello Version: TLS 1.2 (0x0303) Session ID: 13564734eeec0a658830cd… Cipher Suites Length: 34Handshake Protocol: Server Hello Version: TLS 1.2 (0x0303) Session ID: 13564734eeec0a658830cd… Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
会话复用
解决服务器存储会话 ID 成本,负担问题
Session Ticket
类似于 Cookie
服务器加密会话信息,用 New Session Ticket 消息发送给客户端,由客户端存储
客户端使用扩展“session_ticket”发送“Ticket”,服务器解密后验证有效期,然后开始会话,开始加密通信
重连方法
会话票证
实现了0-RTT
预共享密钥
HTTPS优化,解决连接太慢
GlobalSign
ACME 自动化部署
只有 90 天有效期,在 crontab 设置定时任务,定时更新
Let’s Encrypt
网站
收费
应当同时申请 RSA 和 ECDSA 两种证书,Nginx 配置双证书验证
RSA 证书私钥至少要 2048 位,摘要算法应该选 SHA-2
注意要点
申请证书
在 listen 指令后面加上参数 ssl,再配上证书文件
为了提高 HTTPS 的安全系数和性能,还可以强制 Nginx 只支持 TLS1.2 以上协议,打开“Session Ticket”会话复用
密码套件以服务器套件优先,避免客户端选择较弱套件,密码套件看齐 TLS1.3,只使用 ECDHE、AES 和 ChaCha20,支持“False Start”
如果服务器使用了 OpenSSL 分支 BorringSSL,使用特殊“等价密码组”
如果客户端没有 AES 优化,服务器会优先选择与 AES“等价”的 ChaCha20,让客户端能快一点
Nginx
配置 HTTPS
多个域名可以在同一个 IP 地址上运行
Web 服务器会使用请求头里的 Host 字段来选择
虚拟主机
HTTPS 里请求头只有在 TLS 握手后才能发送,握手时必须选择“虚拟主机”对应的证书,TLS 无法得知域名信息,只能用 IP 区分,早期时候,每个 HTTPS 域名必须使用独立 IP
作用和 Host 字段差不多
客户端会在 Client Hello 时带上域名信息,也是在 Nginx 配置
解决办法 TLS 扩展,给协议增加 SNI(Server Name Indication)“补充条款”
服务器名称指示
Nginx 配置做重定向,将 HTTP 的站点跳转到 HTTPS
重定向增加网络成本
安全隐患:重定向响应被中间人篡改,实现“会话劫持”
一定要利用 HSTS(HTTP 严格传输安全,HTTP Strict Transport Security)技术来消除安全隐患
告诉服务器,这个网站,必须严格使用 HTTPS 协议,半年内不允许用 HTTP
HTTPS 服务器需要在发出的响应头里添加一个“Strict-Transport-Security”字段,再设置一个有效期
Nginx 使用 add_header 添加“HSTS”
重定向跳转
HTTPS 迁移
HTTP 没有 2.0,2.1的版本区别,之后将是 HTTP/2,HTTP/3
HTTP/2 要求必须实现的密码套件是“TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256”
HTTP/1.1,1.0 造成了很多混乱和误解,不容易区分差异,所以 HTTP 不再使用小版本号
HTTP/2 所有头字段必须全部小写
为了兼容,HTTP/2 把 HTTP 分成了“语义”和“语法”
如请求方法
头字段等概念不变
“语义”层不动
“语法”层天翻地覆,变更了 HTTP 报文的传输格式
兼容 HTTP/1
HTTP/1里面,请求头用了大量的明文,传输体积太大
HTTP/2里面对请求头进行了“头部压缩”
在客户端和服务器两端建立“字典”
用索引号表示重复字符串,还用哈夫曼编码来压缩整数和字符串,压缩率可达 50%~90%
HTTP/2 没有使用传统压缩算法,开发了专门的“HPACK”算法
头部压缩
这样做效率提高,方便计算机解析
HTTP/2的报文不再使用明文,全面采用了二进制格式
向 TCP/IP 协议靠拢了
把原来的“Header+Body”打散为二进制“帧”(Frame)
“HEADERS”帧存放头数据
“DATA”帧存放实体数据
二进制格式
同一个消息往返的帧会分配一个唯一的流 ID
流,一个概念,是二进制帧的双向传输序列
“流”是虚拟的,在 HTTP/2 可以在一个 TCP 连接上用“流”同时发送多个“碎片化”消息,
多个往返通信都复用一个连接来处理
多路复用
TCP 层面还是有序的
“流”的层面上,消息是有序的“帧”序列
多个请求 / 响应之间没有顺序,不需要排队
不会出现“队头阻塞”,降低了延迟,提高了连接的利用率
连接层面上,消息确实乱序收发的“帧”
HTTP/2添加了一些控制帧来管理虚拟“流”,实现了优先级和流量控制
如 浏览器要请求 HTML 的时候,提前把会用到的 JS、CSS 文件发送给客户端,减少等待的延迟
服务器推送(Server Push 或 Cache Push):服务器可以新建“流”主动向客户端发送消息
虚拟的“流” (Stream)
出于兼容性考虑,HTTP/2可以像 HTTP/1一样使用明文传输数据,不强制使用加密通信,格式还是二进制,只是不需要解密
在主流浏览器上只支持加密的 HTTP/2
h2 表示加密的 HTTP/2
加密
h2c 表示明文的 HTTP/2 ,c 是 clear text
区分
HTTP/2标准制定在 2015 年,已经发现了很多 SSL/TLS弱点
在 TLS1.3 还未发布,所以 HTTP/2加密版在安全方面做了强化,要求下层通信协议必须在 TLS1.2以上
还要支持向前安全和 SNI,并且把几百个弱密码套件列入“黑名单”
HTTP/2 是建立在“HPack”“Stream”“TLS1.2”基础上
HTTP/2 特性
TLS 握手成功后,客户端必须发送一个“连接前言”,用来确认建立 HTTP/2 连接
标准的 HTTP/1 请求报文,使用纯文本 ASCII 码格式
请求方法是特别注册的关键字“PRI”
被称为“Magic”意思为“不可知的魔法”
服务器收到这个字符串,就知道客户端在 TLS 使用 HTTP/2 协议
连接前言
必须使用“HPACK”算法压缩头部数据
将起始行里的请求方法、URI、状态码等统一转换成头字段形式
\"伪头字段\"会在名字前加一个“:”
:authority
:method
:status
伪头字段
将常用的头字段定义了一张只读表
客户端和服务端通过查静态表就可以通过 Index 查到具体的请求方法等
比如 2 代表 GET,8 代表状态码 200
静态表
添加在静态表后面,结构相同
采用哈夫曼压缩编码发送,客户端和服务器都得更新自己的动态表
最终只会两边的字典越来越大,但是发送的头部字段小很多,只有一两个字节的代码
动态表
类似于 TCP 的段或者 TLS 里的记录
报头很小,只有 9 字节,非常节省
帧开头 3 个字节表示
长度
第 4 个字节表示
总共定义了 10 种类型的帧
gRPC 利用了可以在标准之外定义其它类型实现扩展
DATA 帧
HEADERS 帧
只要前一帧在同一个流上并且是没有设置 END_HEADERS 标志的 HEADERS,PUSH_PROMISE 或 CONTINUATION 帧,就可以发送任意数量的 CONTINUATION 帧。
CONTINUATION
数据帧
PRIORITY
SETTINGS
PUSH_PROMISE
PING
RST_STREAM
GOAWAY
WINDOW_UPDATE
控制帧
这两个帧里可以携带 32 位的错误代码,表示终止流的原因,它是真正的“错误”,与状态码的含义不同
帧类型
第 5 个字节表示
可以保存 8 个标志位
END_HEADERS 表示数据结束
END_STREAM 表示单方向数据发送结束
常用
帧标志
最后 4 个字节
接收方使用它从乱序的帧里识别出具有相同流 ID 的帧序列
最高位被保留不用,只有 31 位可以使用,上限位 2^31,越 21 亿
流标识符
00010a 表示数据长度 266 字节,01 表示 HEADERS 帧,25 为 0x25(16 进制)转换成二进制为 111 表示设置 PRIORITY 流的优先级,END_HEADERS 表示这一个帧就是完整的头数据,END_STREAM 表示单方向发送结束,后续不会再有数据00 00 00 01 表示流表示符是整数 1,表示这是客户端发起的第一个流,后面的响应数据帧也会是这个 ID,就是 stream[1]里完成这个请求响应
二进制帧
流是二进制帧的双向传输序列
HTTP/2 的核心
帧虽然是乱序收发,但只要是都拥有相同的流 ID,就都属于一个流,在流里,帧是顺序的
“流”是虚拟的,他的顺序由 TCP 来保证
流是可并发的,一个 HTTP/2 连接可以同时多个流传输数据,实现“多路复用”
客户端和服务端都可以创建流,互不干扰
流是双向的,一个流里客户端,服务端都可以发送或接收数据帧
流之间没有固定关系,彼此独立,流内部的帧有严格顺序
流可以设置优先级,让服务器优先处理
流 ID 不能重复,只能顺序底层
客户端发起的 ID 是奇数,服务器发起的 ID 是偶数
在流上发送“RST_STEAM”帧可以随时终止流,取消接收或发送
第 0 号流比较特殊,既不能关闭,也不能发送数据帧,只能发送控制帧
流的特点
当 ID 用完的时候,再发一个控制帧“GOAWAY”,真正关闭 TCP 连接
流与多路复用
HTTP/2 借鉴了 TCP,根据帧的标志位实现流状态转换
最开始流都是“空闲”(idle)状态
有了流 ID
流进入“打开”状态
两端口可以收发数据
client->server 发送 HEADERS帧
client->server 发送请求
流进入“半关闭”状态
意味着客户端的请求数据已经发送完成
client->server 发送 END_STREAM 帧
server -> client 发送数据
数据发送完毕
server -> client 发送 END_STREAM 帧
两端都进入关闭状态,流结束
流程图
流 ID 不能重用,流的生命周期就是从流开始到流关闭就是一次通信结束
下次再发请求就要开一个新流
流 ID 不断增加,直到到达上线,发送“GOAWAY”帧开一个新的 TCP 连接,流 ID 就可以重头计算
流状态转换
HTTP/2内核剖析
HTTP/2虽然用了“帧”,“流”,“多路复用”,在应用层没有了“队头阻塞”,但是在 TCP 层还是会发生“队头阻塞”
基本上解决了队头阻塞
“丢包重传”机制
当 TCP 发出 N 个段,有其中一个段没有收到回复,那么,其它的回复都会在TCP 协议栈中暂存,等那个没有收到回复的重发,然后收到回复再一起发送到上层
TCP 在这里会把 http 中的包拆分成更小的包,这里叫段 segment
例子:TCP 发送了1,2,3 个包,服务端收到了 2,3 两个包并做出回应,TCP 把 2,3 两个包的回复数据暂存在缓冲区,重发 1 包的数据,等收到 1 包的回复数据再把整体发送给上层
这种队头阻塞是 TCP 固有的
TCP 队头阻塞原因
就算 HTTP/2 解决的再好,也解决不了 TCP 上的队头阻塞问题
HTTP/3 的出现,完美的解决了队头阻塞问题,HTTP/3 原名 QUIC,全称 HTTP over QUIC
HTTP/2的“队头阻塞”
HTTP/3 协议栈图
QUIC 是指 iQUIC 也叫 QUIC-transport
把 TCP 换成了 UDP,并且把 TCP 的连接管理、拥塞窗口、流量控制搬过来了
处于传输层,和 TCP 平级
混合了 UDP、TLS、HTTP,属于应用层
QUIC 最早是由 Google 发明,被称为 gQUIC
把应用层部分分离出来,放到了传输层,形成了 HTTP/3
原来的 UDP 部分“下放”到了传输层
目前由 IETF 标准化的 QUIC 被称为 iQUIC,两者差异非常大
发展
基于 UDP,无需“握手”和“挥手”,比 TCP 快
引入了类似 HTTP/2 的“流”和“多路复用”,单个“流”是有序的,可能会因为丢包而阻塞,但其他“流”不会受到影响
采用加密通信,抵御篡改和“协议僵化”,防止网络中间设备识别协议细节
使用了 TLS1.3,获得了 0-RTT、1-RTT 连接的好处
并不是建立在 TLS 之上,是内部“包含”了 TLS,使用自己的帧“接管”了 TLS里的“记录”,握手消息、警报消息都不使用 TLS 记录,是封装成 QUIC 的帧发送,节省了一次开销
特点
详细的看 https://quicwg.org/
QUIC 和 TLS 是相互协作的关系
基本数据传输单位是包(packet)和帧(frame)一个包由多个帧组成,包面向的是“连接”,帧面向的是“流”
QUIC使用“连接 ID”来标记通信的两个端点,这个连接 ID 是在握手阶段生成的
连接 ID 代替了 TCP 中的“IP 地址+端口”,支持连接转移
TCP 必须重新建立连接
QUIC 因为两端使用的是连接 ID,所以没有出现逻辑上的终端,可以继续使用 IP 变化之前的连接
连接转移:比如,你在家里用的 WIFI,突然断网了,转换成 4/5G手机流量了,IP 发生了变化,
内部细节
QUIC
HTTP 各协议版本协议栈图
HTTP
0 条评论
回复 删除
下一页