HTTP 协议基础与 HTTPS 加密原理
HTTP 是互联网客户端与服务端之间的无状态传输协议,定义了请求响应格式、方法(GET/POST)、报头及状态码。Cookie 与 Session 用于维持会话状态。HTTPS 通过引入 CA 证书、非对称加密交换密钥及对称加密传输数据,结合数字签名防止篡改,保障通信安全。本文详细介绍了 HTTP 协议结构、请求响应流程、状态码含义以及 HTTPS 加密原理。

HTTP 是互联网客户端与服务端之间的无状态传输协议,定义了请求响应格式、方法(GET/POST)、报头及状态码。Cookie 与 Session 用于维持会话状态。HTTPS 通过引入 CA 证书、非对称加密交换密钥及对称加密传输数据,结合数字签名防止篡改,保障通信安全。本文详细介绍了 HTTP 协议结构、请求响应流程、状态码含义以及 HTTPS 加密原理。

HTTP(HyperText Transfer Protocol)超文本传输协议,是互联网中客户端与服务器之间传输数据的协议。HTTP 无连接、无状态,每次请求都是独立的,每次请求都要重新创建新链接,需要 session 和 cookie 保存登录信息状态;始终由客户端发送请求,服务端不会向客户端主动发送请求;可以传输多种数据格式,如音频、视频、图片等。
当我们在浏览器输入一个网址时,浏览器会给服务器发送一个 HTTP 请求,服务器收到这个请求之后,经过计算返回一个 HTTP 响应。

客户端是主动访问的一端发起请求的一端,服务端是被动接受请求的一端。请求是客户端发送给服务端的数据,响应是服务端返回给客户端的数据。
了解了 HTTP 就是网络通信的协议之后,我们来大致看看协议请求和响应的协议格式。

请求格式包含请求方法、URL、HTTP 版本、请求报头以及正文;其中元素之间用空格和换行符隔开,用于区分不同元素,用于解决粘包问题。

响应格式包含 HTTP 版本、状态码、状态码描述、响应报头、响应正文。
下面我们来逐一介绍请求中的元素。
URL(Uniform Resource Locator)统一资源定位符,简单说就是我们日常生活中的网址,我们通过这个唯一的 URL 就能访问到特定的资源。
URL 由六部分组成,我们先放上一个网址:
http://www.example.com:8080/product/list?category=book&page=1#top
首先是 http,规定 URL 获取资源的方式,类似的方式还有 https、ftp 等;www.example.com 相当于门牌号,通过这个门牌号我们可以解析出具体的 IP 地址,后面的 8080 就是对应的端口号;/product/list 就是在该地址的根目录下所要访问的具体文件;接下来就是客户端向服务端传递的参数,由 ? 进行划分,传递第一个参数 category = book,第二个参数 page=1,参数之间用 & 分隔;最后是片段,用 # 分隔,用来定位网页的具体位置。
核心请求方法有五种:GET、POST、PUT、DELETE、PATCH;我们日常使用的 GET、POST 占比最高。
GET 的核心是从服务器中要东西,参数会拼在 URL 当中,因此我们肉眼就可以看见,它的安全性不高,容易暴露参数信息。
https://api.example.com/users?id=123
如此处我们想访问 id = 123 的用户。
POST 的核心是向服务器发东西,参数存放在正文中,URL 看不见;例如我们登录输入账号密码。
https://www.example.com/login
此时我们输入的账号密码会保存在正文当中,不会在 URL 上显示,因此安全性较高。
请求报头用于说明,例如说明客户端浏览器类型、可接受数据格式、是否缓存、是否长连接等。
下面是一些常见报头:
- cookie:携带客户端本地存储的信息,用于记录用户偏好、登录状态信息等。
- content-type:指定正文格式,是传表单数据、JSON 数据还是文件上传等等。
- content-length:请求正文字节数。
- accept:可接受的内容类型,JSON 格式、HTML 格式等等。
- host:请求的主机名和端口号。
- referer:告知当前的请求从何处跳转。
HTTP 有很多版本,HTTP 1.0、HTTP 1.1、HTTP 2.0 等等。
HTTP 1.0 支持 GET、POST 等多种方法,但是只能建立短连接,每次访问都要重新建立新连接。HTTP 1.1 在 HTTP 1.0 的基础上支持了长连接,客户端可以一次发送多个请求,不需要每发送一个请求建立一次连接,大大增加了效率。
状态码是服务端给客户端的实际反馈,任务是否成功、失败的原因是什么等等。
状态码分为五类,它们分别由 1、2、3、4、5 开头:
- 1xx:表示服务器已经接收请求正在响应。
- 100:上传大文件时,服务端告知客户端继续上传。
- 2xx:服务器成功处理数据返回。
- 200:服务器成功返回网络内容。
- 201:服务器文章创建成功。
- 204:删除文章后服务器表示无内容返回成功。
- 3xx:请求资源位置变更。
- 301:永久重定向,访问的资源永久更改位置。
- 302:临时重定向,访问的资源临时更改位置。
- 4xx:客户端存在错误。
- 400:填写表单不正确错误返回。
- 401:访问登录页面时未登录访问失败。
- 403:尝试访问没有权限的页面。
- 404:访问不存在的网络连接。
- 5xx:服务端存在错误。
- 500:服务器崩溃,数据库崩溃。
响应报头的主要作用是告知客户端如何处理数据,或传递服务相关信息。
下面是一些常见报头:
- content-type:指定正文格式,是传表单数据、JSON 数据还是文件上传等等。
- content-length:请求正文字节数。
- content-encoding:告知客户端正文使用的压缩格式。
- location:指定重定向,告知客户端需要跳转的新 URL。
Cookie(小饼干)通常用来记录服务器发送到浏览器的一小部分数据,这份数据在浏览器中保存下来,它用来记录一些用户信息、用户偏好等等。
当用户第一次访问网站时,客户端会在 Set-Cookie 报头中存储用户的信息,类似账号密码等;用户将数据传给服务器,服务器将这份数据传回给客户端浏览器,并在本地浏览器保存下来。在之后的请求当中,每当向这个网站申请访问时都会自动带上这份数据。

如我们打开一个浏览器,随意一个网站左上角处可以找到一把锁,点开里面的 Cookie 和站点数据,内部就存储着浏览器记录的用户在当前网站的一些信息偏好。
有了 Cookie 的存在,当我们使用一些登录平台时不再需要每打开一次网址就登录一次,浏览器保存了用户的账号密码,每当用户访问该网站时,客户端会携带 Cookie 信息一同发送给服务端。
当然 Cookie 也存在着安全隐患,由于 Cookie 存储着本人特有的信息,如若被不法之人恶意窃取,通过一些技术脚本获得到我们的 Cookie 信息,那么它们就可以拿着这些信息冒充我们的身份去访问服务器。
Cookie 格式分为请求头 Cookie 格式和响应头 Set-Cookie,它们的参数都很类似,我们就选 Set-Cookie 来介绍:
Set-Cookie: name=value; [属性 1=值 1]; [属性 2=值 2]; ...
其中 name=value 是必选选项,其余属性都可以自由选择,每个属性之间用分号 + 空格隔开。其中的 name 可以是用户姓名、主题颜色、登录状态等,value 就是键值对应用户 id、颜色、登录情况。
- Expires:设置 Cookie 过期时间,决定了 Cookie 的生命周期,采用格林威治时间,格式如下:Expires=Wed, 21 Oct 2026 07:28:00 GMT(星期几 日 月 年 具体时间)。
- Domain:设定特定的访问域名,该份 Cookie 数据只有访问该域名时才会生效。Domain=.example.com。
- Path:指定访问该域名下的特定路径,我们只能访问根目录下的某一个特定的文件夹。Path=/admin。
- Secure:设定仅允许 https 协议下才允许携带,否则不通过,此处只需填写用户名 Secure(无值,仅写属性名)。
Cookie 虽好,但是它会将用户信息暴露出去,如果是一些账号密码,很容易被一些脚本软件窃取,所以我们需要通过 session 与其进行配合。
用户首次访问服务器时,服务器会为其分配一个特定的 session id,并开辟一块空间储存用户的 session id,通过 Set-Cookie 将 session id 传回给客户端,当客户端再次访问时,就是通过 Cookie 传递 session id 访问网站。这样避免了将敏感信息暴露在外部,而是使用 session id 这种无实际意义的值进行了替代。即使他人拿到了 session id,也需要进行解密才能使用,增加了安全性。
HTTPS 和 HTTP 的区别在于 HTTPS 存在一层保护协议,保证了我们传输的数据不被中间人随意篡改。
常见的加密方式对称加密和非对称加密。对称加密只有一份密钥,客户端用该密钥进行加密,服务端再拿着该密钥进行解密;非对称加密需要两份密钥,一份公钥一份私钥,我们可以使用公钥加密私钥解密,或者私钥解密公钥加密。
接下来我们来探寻一下各种加密方法的可行性。
双方都只存在一份密钥,若密钥没有被破解,那么双方的通信就是安全的。但是服务端不仅仅是和一个客户端进行通信,若客户端数量多,那就需要每个客户端维护一份密钥,大大增大了维护成本。或者在传输的时候临时确定一个密钥,那么这份密钥就需要进行加密传输,若明文传输就会被中间人获取,所以要对密钥进行加密操作,所以又再次绕回了。这个方法行不通。
若只使用非对称加密,只能保证有一方传递的数据是安全的。假如客户端用公钥加密私钥解密,那么服务端传递给客户端的信息就是安全的,服务端用公钥加密后只有客户端用私钥才能进行解密。但客户端传数据给服务端时,用私钥加密公钥解密,若中间人获取了公钥,那么就能拿着公钥对数据进行解密篡改,因此存在风险。

若用两份公钥和私钥看似较为安全,因为非对称加密只能保证一端是安全的,那么用两份不就两端都安全了吗。其实不然,两方都使用非对称加密首先效率大大降低,一次通信就涉及到 4 次加密解密操作,其次若每个客户端需要一份密钥,那么服务端管理成本也相继增加。
首先服务端先将公钥 s 传递给客户端,客户端用该公钥对密钥 c 进行加密传回给服务端,这样服务端和客户端就有了同一份密钥。
若中间人截取了服务端的公钥,将自己伪装的公钥 m 传给客户端,客户端用 m 进行加密后传给服务端时,中间人用私钥 m 进行解密,这样就获得了客户端的密钥。所以这样也是不安全的。

问题的本质在于我们传输的信息无法确定是否被中间人进行了篡改。既然两个人无法解决,那么我们就申请引入第三者。
这里我们引入 CA 证书。
服务端在使用 HTTPS 之前,需要向 CA 机构申请一份数字证书,数字证书里包含申请者信息、公钥信息。服务器把证书传给浏览器,浏览器从中获取公钥,证书就如同身份证,证明服务端公钥的权威性。
在申请证书时,会把公钥和私钥发送给服务器使用。

有了证书,我们还需要一份数据签名,确保数据没有被私自篡改。
我们首先对数据进行散列函数得到一个散列值,用签名者私钥进行加密这个散列值;最后服务端拿到数据进行散列函数得到散列值,并对加密的散列值进行公钥解密最后比对两份散列值是否相同就可以判断内容是否篡改。
服务端与客户端连接后,服务端给客户端传递一份证书,证书包含公钥和服务端域名。客户端拿到证书会对证书进行校验。对签名解密得到一份 hash 值,对证书散列化得到第二份 hash 值,两份 hash 值比对就能确定证书是否更改。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online