Write By CS逍遥剑仙 我的主页: www.csxiaoyao.com GitHub: github.com/csxiaoyaojianxian Email: sunjianfeng@csxiaoyao.com
协议、域名 和 端口 都相同的两个 URL 同源,默认可以相互访问资源和操作 DOM,两个不同源之间通过安全策略制约隔离 DOM、页面数据和网络通信来保障隐私和数据安全。
同源策略限制了不同源的 JavaScript 脚本对当前 DOM 对象的读写操作。例如打开两个同源页面,控制台中执行下面代码,第一个页面 body 被隐藏。
let pdom = opener.document // opener 对象指向第一个页面的 window 对象
pdom.body.style.display = "none"
若不同源页面执行上面代码,会报错:
Blocked a frame with origin "https://www.csxiaoyao.com" from accessing a cross-origin frame.
同源策略限制了不同源站点间读取 Cookie、IndexDB、LocalStorage 等数据。
同源策略限制了通过 XMLHttpRequest 等方式发送数据给不同源的站点。
为兼顾效率,目前的页面安全策略所做的平衡:
最初的浏览器页面都支持引用外部 js、css 等第三方资源文件(如 CDN 服务资源部署在其他域名),但存在 XSS 安全问题,因此引入 CSP 来让服务器决定浏览器中资源的加载和内联 JavaScript 代码的执行。
同源策略限制了不同源页面间使用 XMLHttpRequest 或 Fetch 无法直接进行跨域请求,大大制约生产力,因此引入 CORS 策略安全地进行跨域操作。
不同源的 DOM 是不能相互操纵的,降低了效率,因此引入跨文档消息机制,通过 window.postMessage
的 JavaScript 接口进行不同源的 DOM 通信。
XSS 全称 跨站脚本 (Cross Site Scripting),为与 CSS 区分,简称 XSS,由浏览器 支持页面中第三方资源引用 和 CORS 特性引起,表现为黑客在 HTML 文件或 DOM 中注入恶意脚本实行攻击。现在注入恶意脚本的方式已不局限于跨域实现,但仍沿用了 跨站脚本 的名称。恶意脚本能够:
通过 document.cookie
获取 Cookie 信息,然后通过 XMLHttpRequest 或 Fetch 配合 CORS 上传数据到恶意服务器,恶意服务器再在其他电脑上根据获取的用户 Cookie 模拟登录态并操作
使用 addEventListener 接口监听键盘事件,获取用户输入并发送到恶意服务器
伪造登录窗口获取用户账号密码
严重影响用户体验
反射型 XSS 攻击过程中,恶意 JavaScript 脚本属于用户发送给网站请求中的一部分,随后网站又把恶意 JavaScript 脚本返回给用户。当恶意 JavaScript 脚本在用户页面中被执行时,黑客就可以利用该脚本做一些恶意操作。
Web 服务器不会存储反射型 XSS 攻击的恶意脚本,黑客经常会通过 QQ 群或邮件等渠道诱导用户去点击形如 http://xxx.com/xxx?xss=<script>alert('你被xss攻击了')</script>
的恶意链接。
在 Web 资源传输过程或在用户使用页面过程中修改 Web 页面数据,不牵涉到 Web 服务器。例如通过网络劫持(WiFi 路由器劫持、本地恶意软件劫持等)在页面传输过程中修改 HTML 内容。
存储型和反射型 XSS 攻击属于服务端安全漏洞,基于 DOM 的 XSS 攻击属于前端安全漏洞,共同点是先往浏览器中注入恶意脚本,再通过恶意脚本将用户信息发送至恶意服务器上,所以可以通过阻止恶意 JavaScript 脚本的注入和恶意消息的发送来实现 XSS 防范。
XSS 攻击最终需要上传 Cookie,服务器可以通过 HTTP 响应头来为某些重要数据 Cookie 添加 HttpOnly 标志。使用 HttpOnly 标记的 Cookie 只能使用在 HTTP 请求过程中,恶意代码无法通过 JavaScript 的 document.cookie 方法读取。
通过验证码防止冒充用户提交的危险操作脚本执行;限制输入长度以增大 XSS 攻击的难度。
CSRF 全称 跨站请求伪造 (Cross-site request forgery),黑客利用用户的登录态,并通过第三方站点发起跨站请求。和 XSS 不同,CSRF 攻击不需要注入恶意代码,仅利用服务器漏洞和用户登录状态实施攻击。
假设已有一个转账接口:https://csxiaoyao.com/sendcoin
,同时支持 GET / POST,参数为:目标用户 user 和金额 number。当用户打开黑客页后,黑客有三种方式实施 CSRF 攻击:
<html>
<body>
<h1> 黑客的站点:CSRF 攻击演示 </h1>
<img src="https://csxiaoyao.com/sendcoin?user=hacker&number=100">
</body>
</html>
当该页面被加载时,浏览器会自动发起 img 的资源请求。
<html>
<body>
<h1> 黑客的站点:CSRF 攻击演示 </h1>
<form id='hacker-form' action="https://csxiaoyao.com/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>
当用户打开该站点后,表单会被自动执行提交。
<div>
<a href="https://csxiaoyao.com/sendcoin?user=hacker&number=100" taget="_blank">
点击下载美女照片
</a>
</div>
引诱用户点击链接方式通常出现在论坛或恶意邮件上。
CSRF 攻击的必要条件:
与 XSS 攻击不同,CSRF 攻击不会往页面注入恶意脚本,因此黑客无法获取用户数据。防范的关键在于提升服务器的安全性,如:
在 HTTP 响应头中对 Cookie 设置 SameSite 属性来禁止第三方站点发起的请求携带某些关键 Cookie,SameSite 三个选项:
例如原站点响应头中的多个 Cookie 格式如下,第三方站点发起请求时只会携带其中 b_value 的 Cookie 值。
set-cookie: a_value=avalue_xxx; expires=Thu, 23-Apr-2020 00:00:31 GMT; path=/; domain=.csxiaoyao.com; SameSite=strict
set-cookie: b_value=bvalue_xxx; expires=Thu, 23-Apr-2020 00:00:31 GMT; path=/; domain=.csxiaoyao.com; SameSite=none
可以在服务器端根据 HTTP 请求头中的 Referer(仅含域名信息) 和 Origin(含具体URL路径) 属性验证请求的来源地址。
有些站点因为安全考虑,不想把源站点的详细路径暴露给服务器,因此浏览器提供给开发者一个选项,可以不上传 Referer 值,具体可参考 Referrer Policy。在一些重要场合,如通过 XMLHttpRequest、Fecth 发起跨站请求或发送 POST 请求时,都会带上 Origin 属性。
服务器的策略是优先判断请求头中的 Origin,若没有再根据实际情况判断是否使用 Referer 值。
在浏览器向服务器发起请求时,服务器生成一串 CSRF Token 并植入到当前页面中,如:
<html>
<body>
<form action="https://csxiaoyao.com/sendcoin" method="POST">
<input type="hidden" name="csrf-token" value="iydc9ajDpncYhoadjolcnnc98P987bc">
<input type="text" name="user">
<input type="text" name="number">
<input type="submit">
</form>
</body>
</html>
还可以在用户登录时存储在 head 的 meta 标签中,方便在统一的请求拦截器中获取。当浏览器端发起转账请求时需要带上页面中的 CSRF Token,服务器会验证 Token 的合法性。第三方站点发出的请求将无法获取到正确的 CSRF Token 值而被拒绝。
Web 页面安全问题产生的主要原因是浏览器为同源策略开的两个"后门":支持页面中第三方资源引用 和 允许通过 CORS 策略使用 XMLHttpRequest 或 Fetch 跨域请求资源。为解决这些问题,引入 CSP 限制页面任意引入外部资源;引入 HttpOnly 禁止 XMLHttpRequest 或 Fetch 发送关键 Cookie;引入 SameSite 和 Origin 防止 CSRF 攻击。
单进程架构的浏览器除了不稳定,还存在严重的安全问题。若浏览器被爆出漏洞且未及时修复,黑客就可能通过恶意页面向浏览器注入恶意程序,最常见的是利用缓冲区溢出入侵到浏览器进程内部,甚至穿透浏览器威胁操作系统安全,远比 XSS 漏洞可怕。
现代浏览器被划分为 浏览器内核 和 渲染内核 两个核心模块,其中浏览器内核由 网络进程、浏览器主进程 和 GPU 进程 组成,渲染内核就是 渲染进程。浏览器内核和渲染进程间通过 IPC 通信,如网络资源先通过浏览器内核下载,再通过 IPC 提交给渲染进程;渲染进程经过解析资源、绘制等操作,将最终生成的图片通过 IPC 提交给浏览器内核模块来渲染显示。
渲染进程需要执行 DOM 解析、CSS 解析、网络图片解码等操作,若存在漏洞,黑客很容易利用渲染进程执行下载的恶意网络内容发起攻击。现代浏览器的 安全沙箱 利用操作系统提供的安全技术将渲染进程和操作系统隔离,渲染进程在执行过程中无法访问或修改操作系统中的数据,因此用户将无法获取渲染进程之外的任何操作权限。渲染进程对系统资源的访问则通过浏览器内核的 IPC 通信来实现。
Tips: 安全沙箱最小的保护单位是进程,所以只有多进程的现代浏览器架构才能使用。
由于渲染进程采用安全沙箱,所以在渲染进程内部不能与操作系统直接交互,于是在浏览器内核中实现了持久存储、网络访问和用户交互等与操作系统交互的功能,通过 IPC 与渲染进程交互。
安全沙箱阻止了渲染进程的 Cookie、文件缓存 等直接访问文件系统。例如 Cookie,浏览器内核会维护一个 Cookie 数据库,当渲染进程通过 JavaScript 读取 Cookie 时会通过 IPC 通知浏览器内核,浏览器内核读取 Cookie 后再将内容通过 IPC 返回给渲染进程。
安全沙箱阻止了渲染进程直接访问网络,需要通过浏览器内核获取网络资源。浏览器内核会对 URL 做额外权限检查,如同源策略、HTTPS 站点是否包含 HTTP 请求等。
通常 UI 程序需要在操作系统提供的窗口句柄上进行绘制和接收键鼠消息。安全沙箱阻止了渲染进程直接访问窗口句柄和监听用户输入,转移到浏览器内核中实现。渲染进程渲染出位图发送到浏览器内核,由浏览器内核将位图复制到屏幕上;所有的键鼠事件由浏览器内核接收,再根据界面状态进行事件调度,如焦点位于地址栏中由浏览器内核处理,位于页面区域内则通过 IPC 将输入事件转发给渲染进程。
最开始 Chrome 划分渲染进程是以标签页为单位,所以一个标签页中多个不同源的 iframe 也会被分配到同一个渲染进程中,很容易让黑客通过 iframe 攻击当前渲染进程。Chrome 几年前开始重构代码,严格按照 同一站点(根域名+协议相同,区别于同源)的策略分配渲染进程。使用站点隔离后,不同站点的 iframe 分配到相互隔离的渲染进程中,即使渲染进程被攻击,也无法继续访问其他站点渲染进程的内容。2019 年 10 月 20 日 Chrome 团队宣布安卓版 Chrome 已全面支持站点隔离。
Tips: 目前所有操作系统都面临两个由处理器架构缺陷导致的很难修补 A 级漏洞——幽灵(Spectre)和熔毁(Meltdown),黑客很容易通过 A 级漏洞攻击渲染进程,因此站点隔离策略很重要。
渲染进程数量和标签页的联系:
rel=noopener
属性,通过链接打开的新标签页会新分配渲染进程,和源标签页不建立连接关系。HTTP 的明文传输数据提交给 TCP 层后,数据会经过用户电脑、WiFi 路由器、运营商和目标服务器,中间的每个环节数据都可能被窃取或篡改,即 中间人攻击,因此引入 HTTPS 来解决。
HTTPS 并非新协议,而是在 HTTP 协议栈的 TCP 和 HTTP 层之间插入一个 安全层 负责数据加密解密操作。
接下来利用这个安全层,一步步实现一个从简单到复杂的 HTTPS 协议。
第一版:使用对称加密
对称加密即加密和解密都使用相同的密钥。览器端和服务器协商确定加密套件(加密方法)和随机数,再使用相同的加密方法将 client-random 和 service-random 混合起来生成一个密钥 master secret,然后进行数据加密传输。但由于密匙明文传输,黑客很容易伪造或篡改数据。
第二版:使用非对称加密
非对称加密指算法有 A、B 两把密钥,其中一把用来加密,另一把就用来解密。服务器将其中的一个密钥作为公钥明文发送给浏览器并对外公开,而另一个作为私钥不对外公开。但非对称加密不仅效率低,且公钥公开,不能保证服务器端发送给浏览器端的数据安全。
第三版:对称加密和非对称加密搭配使用
结合前两版,传输数据阶段依然使用高效的对称加密,而对称加密的密钥采用非对称加密来传输,解决了效率和两端数据安全传输的问题。由于 pre-master 是经公钥加密后传输的,因此黑客无法获取并生成密钥,也就无法破解传输过程中的数据。
第四版:添加数字证书
第三版已经完美地实现了数据的加密安全传输,但无法解决 DNS 劫持问题,黑客仍然可以替换目标 IP,在恶意服务器上生成公钥私钥,即无法证明"我就是我"。因此浏览器引入了 数字证书 (Digital Certificate),由权威机构 CA (Certificate Authority) 颁发。
数字证书里包含了服务器公钥,浏览器端也增加了证书验证的操作。由于证书是由 CA 签名过的,无法伪造,所以浏览器实现了对服务器的身份认证。
首先准备一套私钥和公钥并向 CA 机构提交相关信息(不含私钥),审核通过后 CA 会签发数字证书,包含各种明文信息(准备的公钥、组织信息、CA 信息、有效时间、证书序列号等) 和一个 CA 生成的签名。
CA 生成签名: 首先 CA 使用 Hash 函数计算证书的明文信息并得出信息摘要;然后再使用 CA 的私钥 对信息摘要进行加密,密文即为 CA 签发的数字签名。可通过数字签名来验证证书是否是该 CA 颁发的。
浏览器向服务器发出请求时,服务器会返回 CA 签名过的数字证书给浏览器。浏览器需要验证 证书有效期、证书是否被 CA 吊销、证书是否由合法的 CA 机构颁发。
验证数字证书是否被吊销: 通常有两种方式:下载吊销证书列表 CRL (Certificate Revocation Lists) 和在线验证 OCSP (Online Certificate Status Protocol)。
验证证书是否由合法的 CA 机构颁发:浏览器使用签名时相同的 Hash 函数计算证书明文信息并得到信息摘要对比用 CA 公钥解密签名数据得到信息摘要,若一致则可以确认证书合法。
注意: 这里的 CA 公钥不是当前证书的公钥,而是颁发证书的 CA 的公钥,CA 证书一般随同当前网站证书部署在服务器中;若未部署则浏览器通过网络下载,一般不推荐。
前面只验证了 CA 的来源可靠性,但浏览器不能确定 CA 机构的合法性。目前通过 WebTrust 认证的根 CA 有 Comodo、geotrust、rapidssl、symantec、thawte、digicert 等,这些根 CA 机构的根证书都内置在各大操作系统中,只要能从 数字证书链 往上追溯到这几个根证书,浏览器就会认为使用者的证书是合法的。
数字证书链: 根证书(自签名证书)是最权威的机构在浏览器中内置的为自己签名的数字证书,一个根CA(Root CAs)会认证很多中间CA(Intermediates CAs),形成数字证书链。
浏览器默认信任操作系统内置的根证书,但黑客也可能向系统中添加恶意根数字证书,所以 HTTPS 只是加固了安全防线,并非绝对安全。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。