我们看到大部分网址前面都有一个 http 或者 https,它其实是应用层的协议方案名,本文讲的就是其中的 http。
协议这种东西,虽然能自己定义,但是已经有大佬定义了一些非常好用的,我们可以直接参考使用。
在互联网世界中,HTTP(HyperTextTransferProtocol,超文本传输协议)是一个至关重要的协议。 它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。HTTP 协议是一个无连接、无状态的协议,即每次请求都需要建立新的连接, 且服务器不会保存客户端的状态信息。
HTTP协议请求与响应格式
请求:
请求方法如下:
其中最常用的就是 GET 方法和 POST 方法。
GET用于想服务器获取资源,POST向服务器传输资源,但其实GET也可以进行数据传输。
当使用GET向服务器发送请求时,可以将参数放到URL中,而POST将参数放到正文中。
响应:
状态码如下:
具体的状态码还具有小差别,比如都是 2 开头,200 表示访问网站首页,服务器返回网页内容,而 201 表示发布新文章,服务器返回文章创建成功的信息。
Cookie和Session
Cookie
打开一个网站时,他可能会让你填写信息用于登录,填写信息后,第二次打开,它可能不会让你再次登录,但是一段时间后,可能又让你登录了。HTTP 明明是无状态,无连接的协议,是如何实现这种效果的呢?
控制这个的,是 HTTP 协议的一个报头Cookie。Cookie 是服务器发送到用户浏览器并保存在浏览器上的一小块数据。当用户第⼀次访问网站时,服务器会在响应的 HTTP 头中设置 Set-Cookie 字段,用于发送 Cookie到用户的浏览器,之后浏览器就会在 HTTP 请求头中自带 Cookie 字段,所以就不需要再次登录了。
HTTP 存在一个报头选项叫做 Set-Cookie ,它可以给浏览器设置 Cookie 值。Set-Cookie 有许多字段,比如 username,expires,path,domain 等。这里介绍比较重要的三个字段的含义:
username: Cookie 的名称和值,用于标识用户。
expires: 用于指定 Cookie 的过期时间。
path: 定义 Cookie 的作用范围。
Cookie 除了能进行用户认证和会话管理,它还有跟踪用户行为,缓存用户偏好等功能。Cookie 功能强大,但也能看出一些安全问题:用户的隐私数据被保存在浏览器,也就是客户端,这样容易被盗取,用户的私密数据就会泄漏。
Session
Session 是服务器用来跟踪用户与服务器交互期间用户状态的机制。与 Cookie 不同,Session 是存放在服务端的,当用户首次访问网站时,服务器为用户创建一个唯一的 Session ID,通过 Cookie 将其发送到客户端。
Cookie 是一个字符串,在客户端与服务端的交互中不断流通,如果用户的隐私数据放在里面,泄漏风险非常大。
Session 是服务端的一个 “容器”,有了它之后,用户的隐私数据就不需要放在 Cookie 中而是放在 Session 中,这样不仅减少了数据的流通泄漏概率,还让用户的数据更安全(因为通常情况下,服务端的安全工作做的都是比客户端好的)。
但这种安全也不是绝对的,因为 Cookie 仍会流通一个必要的 Session ID,如果被人得到这个 Session ID,别人也可以假冒用户对服务端数据进行访问。所以还有 HTTPS 协议和 HttpOnly,Secure 等 Cookie 属性来增加安全性。
HTTPS
HTTPS也是一个应用层协议,是在 HTTP 的基础上引入一个加密层来构成的。
加密就是把明文数据经过变换,生成密文的过程,解密反之。而在加密解密过程中,辅助进行的数据就叫做密钥。加密的方式有对称加密和非对称加密。
比如通过按位异或进行一个简单的对称加密:
明文:a=1234,密钥:key=8888。密文:a^key = 9834。
非对称加密需要两个密钥,一个叫做公钥,一个叫做私钥:
用公钥进行加密的数据,通过私钥进行解密,反之同样可以。非对称加密的算法比较复杂,不适合讲具体的例子,但可以通过一个生活上的简单例子进行理解:
a 要给 b一些文件,因为某些原因他们不能安全及时地交互,于是 a 与 b 进行约定:
b 说:我的桌子上有一个盒子,上面有一把锁,你可以放心把文件放在里面并上锁,只有我有钥匙。
这个例子中,锁就是公钥,钥匙就是私钥。公钥不怕泄漏,而私钥只有特定人持有,并且有私钥的人才能解密,而且非对称加密的效率是比较低的。
中间人攻击
在客户端与服务端的交流中,有人可以通过特殊手段横插一脚,让 客户端的数据先发给它,然后它在转发给服务端,服务端有数据要发送给客户端时,它也能截取到。数据加密就是为了放在数据泄漏的,经过刚才对加密的理解,我们有以下加密方案:
方案一,只有对称加密。为了进行加密,客 服两端需要先进行密钥的协商,如果在这个协商的过程中,被中间人截取到密钥,那么后面的数据加密工作就形同虚设。
方案二,只有非对称加密。服务端有公钥S和私钥S',把 公钥S发给客户端,于是客户端使用 公钥S 进行加密数据再传输,中间人可以截取到 公钥S ,但没有密钥无法解析,看似安全(后面讲)。
方案三,双方都用非对称加密。此时客户端有公钥C和私钥C',服务端有公钥S和私钥S'。双方进行公钥的交换,这样客户端用服务端 公钥S 加密数据,服务端用 私钥S' 进行解密,同理服务端用客户端发来的 公钥C 加密,客户端用自己的 私钥C' 解密。这样的方式好像可以,但效率低下,而且安全问题也没有得到很好解决(后面讲为什么)。
方案四,非对称加密 + 对称加密。服务端有非对称公钥S 和 私钥S'。客户端发起请求,获取 公钥S,然后在本地生成对称密钥C,通过公钥S加密客户端密钥C,发送给服务器。但这仍然无法解决安全问题。
对于方案二三四的安全问题解释:中间人在请求开始前就已经介入,当服务端向客户端发送密钥协商时,中间人截取信息,此时中间人拥有 密钥S,于是它自己形成一套新的 公钥M 和 私钥M'。把自己的 公钥M 发给客户端,而从客户端来的数据,中间人也通过自己的密钥加密再发给服务端。至此 方案二,方案三 和 方案四 全部失败。
总结一下,方案一无法实现密钥解析权力的唯一,方案二三四虽然解决了方案一的问题,但还无法保证密钥的真实可靠,所以仍然有安全问题。
CA机构与证书
以上方案的痛点,在于客户端无法对服务端完全信任,如果有一个权威的机构出来做背书,那么问题就可以得到解决,这种机构叫做CA机构。
服务端在使用 HTTPS 之前,需要向CA机构申请一份数字证书,里面包含申请者信息,公钥信息等,就如同身份证一样,证明服务端公钥的权威性。
除了证书之前,先了解两个概念,数据摘要和数字签名:
数据摘要:把任意长度的原文通过哈希算法,算出一段固定长度的唯一“指纹”,这个指纹就是数据摘要,也叫数据指纹。
数字签名:对数据摘要进行加密,得到的结果就是数字签名。
如果你的服务器为了提供 HTTPS 服务,想要申请一份证书,你需要用你的公钥和域名信息生成CSR文件,把它提交给 CA 机构,CA机构做好审核,会对你申请的证书明文形成数据摘要,用 CA 自己的私钥,给 CSR 里的公钥签名,输出正式的证书给你。
服务端有了合法证书之后,就有了第五种加密方案:非对称加密 + 对称加密 + 证书认证。
在 客户端 和 服务端 建立连接时,服务端返回一个证书,客户端对这个证书进行校验,包括有效期判断,是否受信任判断,验证证书是否被篡改(使用 CA 公钥解密证书签名,得到摘要 hash1;再计算证书内容的摘要 hash2,对比 hash1 与 hash2,相等则证书未被篡改),如果检验通过,那么 客户端 与 服务端就可以正常进行加密通信了。
但是,有没有可能,中间人直接把证书掉包呢?证书如果被更改可以查出来,但要是中间人自己也申请一份证书,用它自己的证书对服务端真正的证书进行掉包,不还是有问题吗?
这种情况一般不会发生,因为证书是包含域名的,假如目标网站是 www.baidu.com,中间人想搞事,他要去 CA 申请一张域名是 www.baidu.com 的证书,但是 CA 会验证这个申请人是否合法,是否真的拥有控制这个域名,如果它用别的域名申请,然后在数据传输时进行掉包,客户端也能发现域名变了。
那么,中间人能不能给自己签名呢?如果它自己造一对公私钥,自己签发一张假证书,域名写成 www.baidu.com呢?这也不用担心,因为浏览器内置了它信任的 CA 机构,如果证书的签发者不在可信任的 CA 列表中,就会弹出警告。