抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

前言

说起 HTTP 协议让我想起了之前做的 socket 聊天,自己定义了一套规则 比如定义一个特殊字符 socket 读到了这个特殊字符 就代表这是一整句结束 显示到界面,发送文件还定义的是一个 Magic Number 告诉 socket 不要按照字符串解析了。

现在想起来 我当时做的事情就是自定义协议 用来规范客户端和服务端的通讯 而 HTTP 协议就是干这个事情的 来规范服务器和客户端的请求&响应标准。

简单介绍 HTTP

HTTP 是基于 TCP/IP 协议,也叫超文本传输协议(HyperText Transfer Protocol) 默认端口 80。

在 《图解 HTTP》 书中指出正确的名字应该叫做 超文本转移协议。

特点

  • 请求&响应: 客户端发送请求 服务器响应请求

  • 无状态(stateless): 在传输过程中 HTTP 不会保留之前的历史信息 等待服务器响应之后 断开连接 要传输数据时必须重新连接。

之所以 HTTP 设计足够简单 是为了更快的处理大量事务 确保协议的可伸缩性

因为无法保留用户的数据,所以后面引入了 cookie 机制 这里就不做介绍了。

命令

在 HTTP 中一共 10 种命令(也就是我们现在所说的方法 Method) 来告诉服务器应该采用哪些方式处理

方法 说明 协议版本
GET 获取资源 1.0/1.1
POST 传输实体主体 1.0/1.1
PUT 传输文件 1.0/1.1
HEAD 获取报文首部 1.0/1.1
DELETE 删除文件 1.0/1.1
OPTIONS 查看支持的方法 1.1
TRACE 追踪路径 1.1
CONNECT 连接代理 1.1

LINK 和 UNLINK 已经在 1.1 的版本中移除

这里最常用的还是 GET/POST 如果你的服务是 RESTful 接口 那应该会用到 PUT/DELETE/OPTIONS

报文

在 HTTP 传输的信息叫做 HTTP 报文 ,报文是由 (报文首部) 和 (报文主体) 构成 它们就是由数据构成的字符串文本。

HTTPS 介绍

由于 HTTP 是明文传输,所以很容易遭到中间人攻击 ,所以使用了 SSL 来进行加密 HTTP 传输内容,SSL 和 HTTP 的组合使用 叫做 HTTPS。

它是在 HTTP 之上 添加了一层加密协议,客户端和服务端每一次传输的数据都需要经过一层特殊处理 即 加密/解密 所以在速度上逊于 HTTP,这个东西的目的只有一个: 保证你发送/接收的数据都是你的服务器在处理 ,因为在 HTTPS 没有出现之前 如何保证你接收的数据是来自你的服务器 是一个难题。

然而 SSL 并不是为了 HTTP 加密而开发的加密技术,SSL 最初是由网景公司开发 不认识?最先开发浏览器那家公司 ,3.0版本之后交给了 IETF。

我们大致了解了这两个协议之后 来看看这个 S 到底安全在哪里?

对 HTTP 进行中间人攻击

或许你现在正在遭受你的运营商使用中间人攻击 篡改数据 添加广告来实现盈利,这是经常发生的事情 但是放心 我的网站已加上了 HTTPS 所以不会出现这种情况。

如果你是 windows 可以使用 Wireshark,MacOs 使用大名鼎鼎的花瓶(Charles),

通过 Charles 进行拦截,拦截后我们能看到在 Charles 拦截时 HTTP 使用明文传输 所以我们可以利用并更改这些数据。

在我攻击的那几秒中 发生了什么?

HTTP 在传输的过程中 是以明文传输的,如果这里面包含了你的密码 中间人一样的能够获取到并用你的身份来进行操作,尽管有的网站对密码进行了加密 中间人只需要获取到登陆之后的 cookie 即可 来完成身份的伪造。

对 HTTPS 进行中间人攻击

这次就选用本站来做个演示。

能看到正常访问情况下 在地址的前面会带上一个小锁的标志,这代表当前的网站是安全的即使用了 HTTPS

按照同样的方法来进行中间人 但是在一开始的时候 就出现了问题

能看到在花瓶中 无法解析这个数据包 请求前面也有一个小锁的标志 接下来该怎么办呢?

这个时候就需要明白这个 S 到低做了什么?

先来说一说这个 HTTPS 采用的加密算法

HTTPS 是采用 SSL 的非对称加密算法也叫公开密钥密码。

所谓非对称加密算是指加密和解密的密钥都不是同一个,明文加密后能够获取到两个密钥 一个叫做公钥(public key)在互联网进行传输的,还有一个叫做私钥(private key) ,它们应该成套出现 需要注意的是 公钥和私钥都能够用来加密和解密

用公钥加密用私钥解密叫做加密传输
用私钥加密用公钥解密叫做认证签名

对称加密刚好是相反,它指加密和解密秘钥都是用的同一个,通过秘钥加密明文 也通过秘钥解密密文 这种算法安全性取决于秘钥的安全性 因为秘钥一旦丢失 获取到的密文可以直接进行解密 也就无任何安全可言了。

在 HTTPS 中,如果使用了对称加密算法 那如何保证秘钥安全的送达客户端?我们又好像回到了最开始的问题 ,如果不发送秘钥 浏览器拿到了密文也无法进行解密 ,发送了秘钥中间人也能获取到 那就无意义了 这是一个死循环。

为了大家更好的理解非对称加密的特点,我举一个例子。

我生成了一套密钥,并把公钥写在了我的网站上。(公钥公开 私钥保留)

你现在想给我发送邮件,但是想加密邮件的内容 所以就使用了我的公钥加密了邮件的内容 并且给我发了过来

我收到邮件后发现是一串密文,我尝试用我的私钥解密 发现解开了 这个时候我就知道有人用我的公钥给我发送了邮件

以上就完成一次数据的加密传输,尽管私钥和公钥在数学上面有一些关联 但是想要破解真的是太难了。

由于 SSL 有两个密钥,发送的密文使用公钥进行加密的 私钥并不会传递 所以就有了第三方的数组认证机构 (CA,Certificate Authority),而现代浏览器比如 Chrome 在开发时就会注入主流的认证机构密钥(公钥和私钥),所以我们如果想要给网站加上 HTTPS 支持 只需要向第三方机构申请安全证书即可 剩下的浏览器会帮我们处理。

即使这样真的可以防止中间人攻击吗?你如何保证第三方认证机构不会把证书授权给那些不法分子呢?因为信仰不同? 你想多了 只要赚钱 这些第三方一样的会把证书发布给他们。在花瓶中 是能够处理 HTTPS 的数据包 因为花瓶自带了证书(笑)

先来打开 SSL 代理

看到了吗?我们一样能够获取到内容,那有的人就会问了 不是说 HTTPS 可以保证安全吗?为什么还能够进行中间人攻击? 接下来就要介绍 SSL 的第二个特征

SSL 数字证书

上面说到过 ,使用私钥加密用公钥解密的表示认证签名 还是举一个例子来说明

我发布了一篇文章,这个时候如何证明文章是我本人发的?我会在文章最底部留下一串密文

这个密文是通过文章内容 MD5 之后的密文 然后再通过我的私钥加密的
private_key.encode(MD5.encode(article.content));

大家因为都有我的公钥,所以去尝试解密 如果这里解密失败 不用想了 不是我发的,如果解密成功发现得到了一串 MD5 然后自己加密文章内容 看一看出来的结果是不是我给的 MD5 如果正确就代表这篇文章确实是我本人发的 如果不正确就是被中间人修改了。

因为中间人并不知道我的私钥,一旦文章的内容发生改变 MD5 值就会发生改变,匹配不上 大家自然知道这个文章并不是本所发 如果这个时候中间人自作聪明独自修改了我给的密文 ,那就更简单了 只要它修改了 大家都有我的公钥 通过我的公钥必定解密失败 解密都失败了 那就更不是本人发的了。

这个就是数字证书的作用: 确保数据不被中间人修改。

介绍完了数字证书,继续演示中间人攻击

如果你使用的是 Chrome

能看到浏览器已经知道当前网站被中间人攻击了。

HTTPS 使用了混淆加密

因为 HTTPS 在性能上远不如 HTTP,大概是 2-100 倍 但是使用者基本感觉不到 为什么? 因为1毫秒的100倍也才100毫秒 谁能感觉到呀!

不过 HTTPS 还是给出了一个比较合理的解决方法,即混淆加密。

什么是混淆加密?我在来举个例子

我和一个小伙伴使用加密的方式聊天,比如使用微信

但是我发现每次都要用私钥解密 公钥加密就太麻烦了呀!

所以我们规定 在第一次发送消息的时候 我们采用非对称加密的方式,然后把对称加密方式的密钥放进来(比如 DES)

后面我们聊天就不用这么麻烦了,因为我们拿到了一个对称加密的密钥 后面的消息过来只需要 decode 就行了 也不用验证是不是对方发过来的 ,因为每次的首次会话 都会改变对称密钥 这样轻松多了。

自造 HTTPS 的可能?

最近在知乎上面看了这个问题,所谓 无知者无畏 为什么我们不能自己造轮子呢?

我们自己定义一套协议 并且不公开 只有公司自己知道加密方式和解密方式 有没有这个可能?

我想这个问题 没有对错 有兴趣的同学可以去知乎看看。

最后

真实的情况可能远远比我文章说的复杂,但是希望这篇文章能让你基本了解 http 和 https 的区别,学无止境。

评论