32 | 同源策略:为什么XMLHttpRequest不能跨域请求资源?
同源
如果两个 URL 的协议、域名和端口都相同,我们就称这两个 URL 同源
同源策略(Same-origin policy)
- DOM
- 同源策略限制了来自不同源的 JavaScript 脚本对当前 DOM 对象读和写的操作
- web数据
- 同源策略限制了不同源的站点读取当前站点的 Cookie、IndexDB、LocalStorage 等数据
- 网络
- 同源策略限制了通过 XMLHttpRequest 等方式将站点的数据发送给不同源的站点
内容安全策略(CSP: Content-Security-Policy)
跨源加载三方文件/资源
CSP 的核心思想是让服务器决定浏览器能够加载哪些资源,让服务器决定浏览器是否能够执行内联 JavaScript 代码
- 定义HTTP头部:
Content-Security-Policy: policy
- 定义:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
通过制定策略,来限制页面允许访问的资源来源
跨域/源资源共享(CORS:Cross-Origin Resource Sharing)
跨源请求数据
通过设置HTTP头,来指定哪些源允许被加载和访问资源Access-Control-Allow-Origin
跨文档消息机制(postMessage)
跨源共享数据
可以允许跨源的页面安全的进行通信otherWindow.postMessage(message, targetOrigin, [transfer])
33 | 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?
什么是 XSS 攻击
XSS:(Cross Site Scripting 跨站脚本) 黑客向HTML或者DOM中注入恶意的脚本,当用户浏览页面是,恶意的script脚本拥有正常脚本所有的权限,这些脚本就会为所欲为的实施攻击
恶意脚本都能做哪些事情
- 窃取 Cookie 信息: 脚本通过document.cookie 获取用户的cookie并上传到恶意服务器
- 监听用户行为:通过 addEventListener 监听用户的键盘输入,获取用户的银行卡账号等
- 修改 DOM:伪造登录窗口,骗取用户的账号密码
- 在页面内生成浮窗广告: 印象用户体验
恶意脚本是怎么注入的
- 存储型 XSS 攻击
存储在漏洞服务器的恶意脚本
- 黑客将恶意脚本存储到有漏洞的服务器上
- 用户访问带有恶意脚本的页面时,加载了有漏洞服务器上的恶意脚本
- 脚本窃取用户的信息,上传到恶意服务器
- 反射型 XSS 攻击
Web 服务器不会存储反射型 XSS 攻击的恶意脚本,这是和存储型 XSS 攻击不同的地方
当用户点击恶意链接时,该链接向服务器发起请求时携带了恶意的脚本(恶意脚本作为请求参数),服务器又将该恶意脚本返回给浏览器,恶意脚本执行攻击用户、窃取用户信息
- 基于 DOM 的 XSS 攻击
不涉及到web服务器
通过劫持网络资源(WIFI 路由器),将恶意的脚本注入到用户的HTML中,不涉及到web服务器
如何阻止 XSS 攻击
- 服务器对输入脚本进行过滤或转码: 如对用户输入的 script 过滤掉或者转码为不可执行的字符
- 充分利用 CSP: 禁止其他域下的脚本执行、向服务器上传数据等
- 使用 HttpOnly 属性: 恶意注入的脚本主要是为了获取cookie,通过设置 http-only 禁止JS执行读取操作cookie
34 | CSRF攻击:陌生链接不要随便点
什么是 CSRF 攻击
CSRF: Cross-site request forgery 跨站请求伪造
黑客通过引诱用户打开自己的链接,在黑客的网站上,利用用户的登录状态发起跨站请求
CSRF攻击需要具备的条件:
- 目标服务器有漏洞
- 用户处于登录态
-
CSRF攻击方式
自动发起 Get 请求
<h1>黑客的站点:CSRF攻击演示</h1>
<img src="https://time.geekbang.org/sendcoin?user=hacker&number=100">
自动发起 POST 请求
<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>
引诱用户点击链接
<a href="https://time.geekbang.org/sendcoin?user=hacker&number=100" taget="_blank">
点击下载美女照片
</a>
如何防止 CSRF 攻击
充分利用好 Cookie 的 SameSite 属性: 通过设置 SameSite 规定哪些请求可以带上cookie
- 验证请求的来源站点:通过请求头总的Origin 和Referer 记录资源发起的网站是否被允许
CSRF Token:浏览器请求服务器时,生成一个 CSRF Token存储到页面,发起转账需求时带上该CSRF Token, 服务器验证该 CSRF Token 是否合法
35 | 安全沙箱:页面和系统之间的隔离墙
安全视角下的多进程架构
单进程浏览器架构的问题:
不稳定:容易导致页面卡顿和浏览器的崩溃
- 不安全:黑客可以通过浏览器内核穿透到操作系统,可以窃取用户文件、监听用户键盘输入
多进程浏览器架构:
浏览器被分为浏览器内核和渲染内核
- 浏览器内核有浏览器主进程、网络进程、GUI进程等,渲染内核有渲染进程,
- 所有的网络资源都是通过浏览器内核中的网络进程请求、下载,然后通过IPC将下载的资源发送给渲染进程
- 渲染进程负责解析JS、HTML、CSS 图片等资源,绘制成图片后将图片通过IPC发送给浏览器内核负责渲染展示
安全沙箱
概念
因为渲染进程可能被黑客攻击,我们在渲染进程和操作系统之间建立一道墙,即使渲染进程被攻击了,也不会影响到操作系统的安全,将渲染进程和操作系统隔离的这道墙,就是安全沙箱。
安全沙箱的影响
因为安全沙箱的存在,渲染进程需要和操作系统交互的功能全部迁移到了浏览器内核中
- 持久存储
- 渲染进程通过JS读取cookie数据,通过IPC发送给浏览器进程,浏览器进程操作后将数据通过IPC发送给渲染进程
- 网络访问
- 用户交互
- 为了防止渲染进程监听用户的鼠标和键盘事件,渲染进程不能直接操作窗口句柄
- 渲染进程 绘制出位图后,将位图发送给浏览器内核显示
- 用户输入的鼠标、键盘事件,没有直接发送给渲染进程,而是传递给浏览器内核,浏览器内核根据任务的类型调度:如是浏览器地址栏操作,则直接在浏览器内核处理,如果是页面上的操作,则浏览器内核通过IPC发送给渲染进程
站点隔离(Site Isolation)
Chrome 将同一站点(包含了相同根域名和相同协议的地址)中相互关联的页面放到同一个渲染进程中执行,之前浏览器实现的是标签级的站点隔离,但是一个标签下如果有多个Iframe,会被黑客通过幽灵(Spectre)和熔毁(Meltdown)这两个浏览器内容攻击,在同一个标签下,通过Iframe 访问读取渲染进程下的数据,所以Chrome目前重构了代码,将所有标签级的站点隔离更改为了Iframe级的站点隔离。36 | HTTPS:让数据传输更安全
在 HTTP 协议栈中引入安全层
第一版:使用对称加密
对称加密是指加密和解密都使用的是相同的密钥
过程:
- 浏览器发送它支持的加密套件列表和client-random给服务器端
- 服务器端选取一个加密套件并生成一个service-random给客户端
- 最后浏览器和服务器分别返回确认消息
- 服务器端和浏览器端用 client-random 和service-random计算生成秘钥
- 服务器和浏览器用秘钥加密数据并传输、解密
问题:
- 服务器端和浏览器端传输random的过程,也可能被中间人攻击拦截,并以此生成秘钥
第二版:使用非对称加密
非对称加密算法有 A、B 两把密钥,如果你用 A 密钥来加密,那么只能使用 B 密钥来解密;反过来,如果你要 B 密钥来加密,那么只能用 A 密钥来解密
过程:
- 浏览器端发送加密套件给服务器端
- 服务器端选择加密套件,并将生成的公钥一起发送给服务器端
- 服务器和浏览器端确认
- 浏览器用服务器发送来的公钥加密数据,发送给服务器,只有服务器的私钥能够解密数据,服务器用私钥加密数据给浏览器端,浏览器用公钥解密数据
问题:
- 非对称加密效率太低
- 无法保证服务器发送给浏览器数据的安全性:浏览器给服务器用公钥加密,只有服务器的私钥能够解密,但是服务器给浏览器的数据,用服务器的私钥加密,黑客也是能够获取到公钥的,用公钥解密服务器的数据,这无法保证服务器数据的安全性
第三版:对称加密和非对称加密搭配使用
在传输数据阶段依然使用对称加密,但是对称加密的密钥我们采用非对称加密来传输
过程:
- 浏览器发送 对称加密套件列表、非对称加密套件列表、client-random给服务器端
- 服务器端保存client-random,选择对称加密套件和非对称加密套件,生成公钥和 service-random,并将加密套件 + service-random + 公钥发送给浏览器端
- 浏览器端保存service-random和公钥,生成一个随机数pre-master并用公钥发送给服务器端,并确认消息
- 服务器端用私钥解密 pre-master, 并返回确认消息(非对称加密)
- 浏览器和服务器用client-random、service-ramdom、pre-master 生成 master-secret 秘钥
- 浏览器和服务器数据传输采用 master-secret 加密、传输、解密数据(对称加密)
问题:
- 解决了数据的加密传输,但是服务器仍然可能被劫持篡改(服务器的身份无法得到认证)
第四版:添加数字证书
权威机构称 CA(Certificate Authority) 数字证书(Digital Certificate)
过程:
- 服务器没有直接将公钥返回给浏览器,而是返回浏览器数字证书,数字证书中有服务器的公钥
-
数字证书的申请和验证
CA生成数字证书
极客时间将信息、公钥发送给CA认证
- CA用Hash函数计算极客时间提交的明文信息,生成信息摘要
-
浏览器验证数字证书
浏览器请求服务器,服务器将数字证书发送给浏览器
- 浏览器用CA同样的Hash函数计算极客时间明文信息得到同样的信息摘要A,用CA的公钥解密数字签名得到信息摘要B,对比信息摘要A和信息摘要B是否一致,如果一致,则合法,否则,则非法
对于浏览器安全,主要是只以下三个方面
- 页面安全
页面安全主要是XSS和CSRF:
XSS:跨站脚本攻击
- 存储型:恶意脚本存储到目标服务器,用户请求页面时,恶意脚本执行
- 反射型:目标服务器不存储恶意脚本,用户请求是携带了恶意脚本,服务器将恶意脚本返回给用户,恶意脚本执行
- 基于DOM型:脚本通过劫持路由器,向用户的HTML注入了恶意内容,影响用户体验
防范:
- 对脚本代码进行过滤和转义
- cookie 配置http-only
- 启用浏览器的内容安全策略:禁止跨域的资源执行、发送数据
CSFR:跨站请求伪造
跨站请求伪造需要满足一下条件:
- 目标服务器有漏洞
- 用户处于登录状态
- 跳转到了第三方网站
处于登录状态的用户点击恶意网站后,恶意网站用当前用户的身份向服务器发起了请求
防范:
- cookie 设置same-site 避免非同源网站使用cookie
- CSRF token: 服务器向用户发送CSFR token, 请求时携带token并校验是否合法
- 在请求头增加referer 和 origin, 验证请求发起的来源
- 系统安全
浏览器在单内核浏览器基础上做的重构,目前的浏览器基本都是多内核的,浏览器内核里的浏览器进程、网络进程和渲染内核的渲染进程,浏览器内核中的网络进程将数据下载后通过IPC发送给渲染内核中的渲染进程,渲染进程解析HTML、CSS、执行JS后绘制成页面图片发送给浏览器进程展示,如果有恶意脚本,也都是在渲染器进程执行的,现代浏览器为渲染进程增了安全沙箱(sandbox)来隔离渲染进程和操作系统,即使渲染进程被攻击,也不会影响操作系统的安全。
- 网络安全
网络安全是指通过在http下一层增加TSL/SSL对数据报文加密解密,避免明文传输遭到黑客的网络劫持
其中HTTPS使用了对称加密和非对称加密混合的方式来加密数据:用非对称加密加密随机数,用对称加密
加密数据报文,这样既保证了数据加解密的效率,又保证了安全