HTTP

HTTP 超文本传输协议构建于 TCP/IP 协议之上,是一个应用层协议,默认端口号是 80.

HTTP 请求由三部分构成,分别为:

  • 请求行
  • 首部
  • 实体

HTTP 协议的主要特点:

  1. 简单快速
  2. 灵活
  3. 无连接
  4. 无状态: 无状态指客户端一次 HTTP 请求完成以后,客户端再发送一次 HTTP 请求,HTTP 并不知道当前客户端是一个"老用户"。可以使用 Cookie 和 Session 来解决无状态的问题。

服务器发送的响应报文包含 Set-Cookie 首部字段,客户端得到响应报文后把 Cookie 内容保存到浏览器中。

HTTP/1.0 200 OK Content-type: text/html Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry [page content]

客户端之后对同一个服务器发送请求时,会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。

GET /sample_page.html HTTP/1.1 Host: www.example.org Cookie: yummy_cookie=choco;
tasty_cookie=strawberry

HTTP 报文的组成部分

http报文包括:请求报文响应报文

请求报文包括:

  • 请求行:包括请求方法、请求的urlhttp协议及版本。
  • 请求头:一大堆的键值对。
  • 空行指的是:当服务器在解析请求头的时候,如果遇到了空行,则表明,后面的内容是请求体
  • 请求体:数据部分。

响应报文包括:

  • 状态行:http协议及版本、状态码及状态描述。
  • 响应头
  • 空行
  • 响应体

短连接与长连接

当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问的 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接,那么开销会很大。

长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。

  • 从 HTTP/1.1 开始默认是长连接的,如果要断开连接,需要由客户端或者服务器端提出断开,使用 Connection : close
  • 在 HTTP/1.1 之前默认是短连接的,如果需要使用长连接,则使用 Connection : Keep-Alive

持久链接/http 长连接

  • 轮询http1.0中,客户端每隔很短的时间,都会对服务器发出请求,这种做法是无奈之举,实际上对服务器、客户端双方都造成了大量的性能浪费。
  • 长连接HTTP1.1中,通过使用Connection:keep-alive进行长连接,。客户端只请求一次,但是服务器会将继续保持连接,当再次请求时,避免了重新建立连接。

注意,HTTP 1.1默认进行持久连接。在一次 TCP 连接中可以完成多个 HTTP 请求,但是对每个请求仍然要单独发 headerKeep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。

长连接中的管线化

如果能答出管线化,则属于加分项。

长连接时,默认的请求这样的:

	请求1 --> 响应1 -->请求2 --> 响应2 --> 请求3 --> 响应3

管线化就是,请求打包,一次性发过去,一次响应回来。

HTTP 方法

  • GET:获取资源
  • POST:传输资源
  • PUT:更新资源
  • DELETE:删除资源
  • HEAD:获得报文首部
  1. get post`比较常见。
  2. putdelete 在实际应用中用的很少。况且,业务中,一般不删除服务器端的资源。

Post 和 Get 的区别?

GET 和 POST 本质上就是 TCP 链接,并无差别。GET 和 POST 有一个重大区别,简单的说:GET 产生一个 TCP 数据包;POST 产生两个 TCP 数据包。对于 GET 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200(返回数据); 而对于 POST,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)。 但是,比如你想在 GET 请求里带 body,一样可以发送 Expect: 100-continue 并等待 100 continue,这是符合标准的。

  • 在使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data。但并不是所有浏览器会这么做,例如火狐就不会。
  • 而 GET 方法 Header 和 Data 会一起发送。
  • 首先先引入副作用和幂等的概念。
  • GET 在浏览器回退时是无害的,而 POST 会再次提交请求。
  • GET 产生的 URL 地址可以被书签收藏,而 POST 不可
  • GET 请求会被浏览器主动缓存,而 POST 不会,除非手动设置。
  • GET 请求只能进行 url 编码,而 POST 支持多种编码方式。
  • GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留。
  • GET 请求在 URL 中传送的参数是有长度限制的(大多数浏览器限制在 2K,大多数服务器在 64K 左右),而 POST 么有。
  • 对参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有限制。
  • GET 比 POST 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息。
  • GET 参数通过 URL 传递,POST 放在 Request body 中。

POST 提交数据的方式

服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说到 POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分。下面就正式开始介绍它们:

  • application/x-www-form-urlencoded

这是最常见的 POST 数据提交方式。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。上个小节当中的例子便是使用了这种提交方式。可以看到 body 当中的内容和 GET 请求是完全相同的。

  • multipart/form-data

这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data。直接来看一个请求示例:

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"

title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。关于 multipart/form-data 的详细定义,请前往 RFC1867open in new window 查看(或者相对友好一点的 MDN 文档open in new window)。

这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还支持 text/plain,不过用得非常少)。

随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,例如 application/jsontext/xml,乃至 application/x-protobuf 这种二进制格式,只要服务器可以根据 Content-TypeContent-Encoding 正确地解析出请求,都是没有问题的。

postman post 的时候 raw 和 x-www-form-urlencoded 的区别

https://blog.csdn.net/wangjun5159/article/details/47781443

Content-Type

  1. form-data 形式因为有 boundary 进行隔离,所以既可以上传文件也可以上传键值对,采用了键值对的方式,所以也可以上传多个文件。最后会被转化为一条信息。
  2. x-www-form-urlencoded 会将表单中的键值对都转化为以 & 相连的键值对字符串。
  3. raw 可以上传任意格式的文本, 如 text xml json 等。 需要注意的是,选择 raw 形式传数据时需要在请求头中携带 Content-Type, 值为 application/json 等。
  4. binary 相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。
  5. multipart/form-data 与 x-www-form-urlencoded 区别: multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息; ​ x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。

HTTP 有以下安全性问题

  1. 使用明文进行通信,内容可能会被窃听;
  2. 不验证通信方的身份,通信方的身份有可能遭遇伪装;
  3. 无法证明报文的完整性,报文有可能遭篡改。

x-www-urlecoded-form 和 application/json 在 post 中的区别

json: 用来告诉服务端消息主体是序列化后的 JSON 字符串

application/json application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦

POST http://www.example.com HTTP/1.1 Content-Type: application/json;charset=utf-8 {"title":"test","sub":[1,2,3]} application/x-www-form-urlencoded 这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样(无关的请求头在本文中都省略掉了):

BASHPOST http://www.example.com HTTP/1.1 Content-Type: application/x-www-form-urlencoded;charset=utf-8 title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3 url 对 key value 进行编码,然后用&链接

multipart/form-data 这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data。直接来看一个请求示例:

BASHPOST http://www.example.com HTTP/1.1 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="text" title ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="file"; filename="chrome.png" Content-Type: image/png PNG ... content of chrome.png ... ------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

HTTPS

HTTPS = HTTP + TLS(早期是 SSL),是一种在加密信道进行 HTTP 内容传输的协议。

HTTPS 为了兼顾安全与效率,同时使用了对称加密和非对称加密。对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输

HTTPS 在传输的过程中会涉及到三个密钥:

  • 服务器端的公钥和私钥,用来进行非对称加密
  • 客户端生成的随机密钥,用来进行对称加密

HTTPS 的工作原理

HTTPS 还是通过了 HTTP 来传输信息,但是信息通过 TLS 协议进行了加密。HTTPS 在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。

TLS/SSL 协议不仅仅是一套加密传输的协议,使用了非对称加密,对称加密以及 HASH 算法。在 TLS 握手阶段,两端使用非对称加密的方式来通信,但是因为非对称加密损耗的性能比对称加密大,所以在正式传输数据时,两端使用对称加密的方式通信。

步骤:

  1. 客户端向服务器发起 HTTPS 请求,连接到服务器的 443 端口,消息中同时包含了它的 TLS 版本,可用的加密算法和 HASH 算法。
  2. 服务器端有一个密钥对,即公钥和私钥,服务器端向客户端返回一个消息,包含了服务器端的 TLS 版本,所选择的加密和 HASH 算法,以及 CA 证书,证书中包含了公钥、颁发机构信息等。
  3. 获得服务器的证书之后,会验证证书的合法性。如果发现发现公钥有问题,那么 HTTPS 传输就无法继续。如果公钥合法,那么客户端会生成一个随机值 ,这个随机值就是用于对称加密的客户端密钥 KEY。
  4. 客户端用服务器的公钥对客户端密钥 KEY 进行非对称加密,这样客户端密钥就变成密文了,并使用约定好的 HASH 算法计算握手消息,发送给服务器。
  5. 服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是客户端密钥 KEY。
  6. 接着用客户端密钥 KEY 对握手消息进行对称加密,发送给客户端。
  7. 客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。浏览器解密并计算握手消息的 HASH,如果与服务端发来的 HASH 一致,此时握手过程结束。
  8. 之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。

从上面的过程可以看到,TLS 的完整过程需要三个算法(协议),密钥交互算法,对称加密算法,和消息认证算法(TLS 的传输会使用 MAC(message authentication code) 进行完整性检查)。

为什么HTTPS安全

因为网络请求需要中间有很多的服务器路由器的转发。中间的节点都可能篡改信息,而如果使用HTTPS,密钥在你和终点站才有。HTTPS之所以比HTTP安全。

HTTPS 加密是在传输层。https 报文在被包装成 tcp 报文的时候完成加密的过程,无论是 HTTPS 的 header 域也好,body 域也罢都是会被加密的。

当使用 tcpdump 或者 wireshark 之类的 tcp 层工具抓包,获取是加密的内容,而如果用应用层抓包,使用 Charels(Mac)、Fildder(Windows)抓包工具,那当然看到是明文的。

TLS 证书机制

HTTPS 过程中很重要的一个步骤,是服务器需要有 CA 颁发的证书,客户端根据自己的信任 CA 列表验证服务器的身份。现代浏览器中,证书验证的过程依赖于证书信任链。

所谓证书信任链,即一个证书要依靠上一级证书来证明自己是可信的,最顶层的证书被称为根证书,拥有根证书的机构被称为根 CA。

既然所有的信任,最终要落到根 CA 上,根证书本身又是怎么获得的呢?答案也很简单,根证书一般是操作系统自带的。不管是桌面系统 Windows,macOS 还是移动端系统 Android, iOS 都会内置一系列根证书。随着操作系统本身的升级,根证书也会随着升级进行更新。

客户端会有一个有效证书串,一般的浏览器都会内置很多常见服务器的这个证书,特殊的服务器就需要前期通过手工将证书添加到客户端。证明对方是否持有证书的对应的私钥,客户端通过比对来确认证书的有效性。

浏览器开始查找操作系统中已内置的受信任的证书发布机构 CA,与服务器发来的证书中的颁发者 CA 比对,用于校验证书是否为合法机构颁发

HTTPS 的缺点

  1. HTTPS 的安全是有范围的,在黑客攻击、服务器劫持等情况下几乎起不到作用。
  2. 在现有的证书机制下,中间人攻击依然有可能发生。
  3. HTTPS 相比 HTTP 无论是响应时间还是耗电量都有大幅度上升。HTTPS 需要更多的服务器资源,也会导致成本的升高。
  4. 因为需要进行加密解密等过程,因此速度会更慢;
  5. 需要支付证书授权的高额费用。这也是 HTTPS 没有大规模应用的原因

HTTP 和 HTTPS 的区别

  1. HTTP 标准端口是 80 ,而 HTTPS 的标准端口是 443
  2. HTTP 的信息是直接与 TCP 进行数据明文传输,HTTPS 则是具有安全性的 SSL 加密。
  3. HTTP 工作于应用层,而 HTTPS 的安全传输机制工作在传输层。
  4. HTTPS 协议需要到 CA 申请证书或自制证书。

中间人攻击

分为两种:

  1. SSL 劫持攻击, 比较常见。
  2. SSL 剥离攻击, 中间人强制 http 请求,自己与服务器之间进行 https 请求。

所谓中间人攻击,指攻击者与通讯的两端分别建立独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。

中间人攻击过程如下:

  1. 服务器向客户端发送公钥。
  2. 攻击者截获公钥,保留在自己手上。
  3. 然后攻击者自己生成一个伪造的公钥,发给客户端。
  4. 客户端收到伪造的公钥后,生成加密 hash 值发给服务器。
  5. 攻击者获得加密 hash 值,用自己的私钥解密获得真秘钥。
  6. 同时生成假的加密 hash 值,发给服务器。
  7. 服务器用私钥解密获得假秘钥。
  8. 服务器用假秘钥加密传输信息

防范方法:

  1. 服务端在发送浏览器的公钥中加入 CA 证书,浏览器可以验证 CA 证书的有效性
  2. 阻止自签名证书。
  3. 强制使用 SSL pinning: 通过 SSL pinning 可以验证客户端检查服务器证书的有效性。
  4. 使用污染小的 DNS 服务器。
  5. 将重要的域名和 IP 地址的映射写到系统 HOST 文件,保护好 HOST 文件不被恶意篡改。
  6. 使用静态 ARP,绑定 MAC 地址和 IP 地址映射,防止 ARP 攻击

charles 抓 https 的原理就是中间人,你信任了 charles 的 CA,他签发了这个网站的证书就能被浏览器信任,所以你能抓包。

加密算法

是否了解公钥加密和私钥加密

一般情况下是指私钥用于对数据进行签名,公钥用于对签名进行验证。

1. 对称加密 AES

对称加密又叫做私钥加密,即信息的发送方和接收方使用同一个密钥去加密和解密数据。加密中用到的密钥叫做私钥,该密钥不能被泄露。

由于对称加密的算法是公开的,所以一旦私钥被泄露,那么密文就很容易被破解,所以对称加密的缺点是密钥安全管理困难。

优点:运算速度快; 缺点:无法安全地将密钥传输给通信方。

2. 非对称加密 RSA

非对称加密使用一对密钥,即公钥和私钥,其安全性更好。私钥被自己保存,不能对外泄露。公钥指的是公共的密钥,任何人都可以获得该密钥。用公钥或私钥中的任何一个进行加密,用另一个进行解密。

非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。

优点:可以更安全地将公开密钥传输给通信发送方; 缺点:运算速度慢。

3. HTTPS 采用的加密方式

HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥,之后使用对称密钥加密进行通信。

证书颁发和验证的流程

Last Updated:
Contributors: yiliang114