为什么会有同源策略?进行详细解析

公众号:小博的前端笔记

同源策略(Same-Origin Policy,SOP)是现代浏览器实施的一项核心安全机制,它出现的主要目的是解决网站间的数据隔离和用户隐私保护问题。以下是其出现的根本原因和核心逻辑:


一、核心目的:防止恶意网站窃取/篡改用户数据

  1. 防范数据窃取 如果没有同源策略,假设你登录了银行网站(A),然后访问了恶意网站(B)。网站B的脚本可以直接向银行网站(A)发起请求,获取你的账户数据(如余额、交易记录)。SOP 阻止了这种跨域数据读取。
  2. 阻止恶意操作 恶意网站可能尝试伪造请求(如转账、修改密码),或通过脚本篡改其他网站的 DOM(如伪造登录表单)。SOP 限制了这类操作。

二、具体风险场景(若无SOP)

  1. Cookie 劫持 用户登录 bank.com 后,浏览器存储了身份验证的 Cookie。若无 SOP,evil.com 的脚本可以发起一个到 bank.com/transfer?to=attacker 的请求,浏览器会自动带上 Cookie 完成转账。
  2. 敏感数据读取 evil.com 通过 <iframe> 嵌入 gmail.com,并尝试用 JavaScript 读取 iframe 内的邮件内容。
  3. CSRF(跨站请求伪造)扩大化 虽然现代防御需结合 CSRF Token,但 SOP 是基础屏障(阻止攻击者读取响应)。

三、什么是"同源"?

同源要求协议(Protocol)+ 域名(Host)+ 端口(Port) 完全一致:

  • 同源https://example.com/ahttps://example.com/b

  • ❌不同源:

    • http://example.com(协议不同)
    • https://sub.example.com(域名不同)
    • https://example.com:8080(端口不同)

四、SOP 如何工作?

  1. 隔离 DOM 访问 禁止跨域页面通过 iframe.contentWindowwindow.open 访问另一个页面的 DOM。

    javascript复制代码

    javascript 复制代码
    // evil.com 的代码
    let iframe = document.getElementById('bank-iframe');
    console.log(iframe.contentWindow.document); // 被阻止!
  2. 限制网络请求

    • XMLHttpRequest / fetch 默认不能跨域读取响应。
    • 跨域请求可发送(浏览器不阻止发送),但响应会被浏览器拦截(除非目标服务器明确允许)。
  3. 限制存储访问 localStorageIndexedDB 等数据按域名隔离,禁止跨域访问。


五、为什么需要额外机制(如 CORS)?

SOP 是"默认禁止",但合法需求(如前端调用 API)需授权:

  • CORS(跨域资源共享) :服务器通过响应头(如 Access-Control-Allow-Origin: *)声明允许的跨域访问。
  • 其他方案 :JSONP(利用 <script> 标签不受限)、代理服务器、postMessage API。

六、特殊情况的例外规则

  1. 部分标签允许跨源加载(但限制访问) <img><script><link> 等标签允许跨域加载资源(CDN、公共JS库等),但无法直接读取资源内容

    html复制代码

    xml 复制代码
    <!-- evil.com 能加载图片,但无法通过JS读取像素数据 -->
    <img src="https://bank.com/user-avatar" id="img">
    <script>
      img.onload = () => console.log(img.width); // ✅ 可获取宽高
      img.onload = () => console.log(img.contentWindow); // ❌ 无权访问
    </script>
  2. 跨域写操作通常允许(需防御CSRF) 表单提交、重定向等写操作一般不受限(如 <form action="...">),因此需配合 CSRF Token 防护。


总结:

1、策略主要限制js的能力

  • 1.无法读取非同源的 cookie、Storage、indexDB的内容
  • 2.无法读取非同源的DOM
  • 3.无法发送非同源的AJAX,更加准确的说应该是发送了请求但被浏览器拦截了,也就是说浏览器会拦截非同源的请求。

2、为什么会有同源策略?

简单来说是为了安全

  • 1.为了防止恶意网页可以获取其他网站的本地数据。
  • 2.为了防止恶意网站iframe其他网站的时候,获取数据。
  • 3.为了防止恶意网站在自已网站有访问其他网站的权利,以免通过cookie免登,拿到数据。
问题场景 SOP的作用 风险示例
用户隐私泄露 阻止跨域读取敏感数据 窃取邮箱内容、聊天记录
非授权操作 限制跨域DOM操作/API调用 伪造转账按钮
身份盗用 隔离Cookie/本地存储 冒用已登录身份发起请求

本质:同源策略将互联网的开放性(超链接)与用户隐私/安全的封闭性(站点隔离)达成平衡。 它在保障基础安全的同时,也通过 CORS 等机制为合法需求开放通道,成为现代 Web 安全的基石。

拓展:为什么协议不同、域名不同、端口不同就不安全了呢

不要问为什么拓展,因为有人会抠这种问题问!

  1. 协议不同 (Protocol) - 例如 HTTP vs HTTPS

    • 安全问题:明文传输与中间人攻击

      • HTTP 协议是明文传输,数据在网络中容易被截获和篡改。HTTPS 则通过 TLS/SSL 提供了加密和身份认证。
      • 假设 https://secure-site.com(安全) 的页面试图通过 XMLHttpRequesthttp://insecure-site.com(不安全)加载资源。
      • 由于 HTTP 请求是明文的,任何网络路径上的攻击者(如公共 WiFi 上的恶意用户)都可以篡改 http://insecure-site.com 的响应内容。
      • 如果浏览器允许 https://secure-site.com 的脚本读取来自 http://insecure-site.com 的数据,那么攻击者就可以注入恶意脚本到 HTTP 响应中,让 https://secure-site.com 的页面执行,从而盗取其敏感信息或执行恶意操作。这破坏了安全来源的完整性。
    • 安全问题:安全上下文降级

      • 从 HTTPS 页面加载 HTTP 资源("混合内容")本身就存在风险。如果允许 HTTPS 页面的脚本直接与 HTTP 服务交互并处理数据,会大大增加安全风险,因为 HTTP 通信本身就不安全。
  2. 域名不同 (Host) - 例如 siteA.com vs siteB.com vs sub.siteA.com

    • 安全问题:钓鱼、会话劫持、数据窃取

      • 会话劫持 (Session Hijacking / Cookie Theft): 这是最直接的风险。evil.com 的页面绝对不能访问 mybank.com 设置和发送的 Cookie,否则你登录银行后的身份凭证就会被盗。Cookie 通常包含会话标识符 (Session ID)。
      • 跨站请求伪造 (CSRF - Cross-Site Request Forgery): 虽然同源策略主要防御读取响应,但它也间接关联到另一个安全问题。恶意网站 evil.com 可以诱导你的浏览器向 mybank.com 发送请求(利用你可能已登录 mybank.com 的状态)。如果 mybank.com 没有额外的防护措施(如 CSRF Token),恶意请求可能会执行转账等操作。严格的不同源限制让浏览器在阻止读取跨域响应方面更明确。
      • DOM 窃取/篡改: 如果 evil.com 的 iframe 嵌入了 mybank.com 的登录页,并且脚本可以自由访问 iframe 内部的 DOM,那么恶意脚本就能读取你输入的用户名和密码,或者修改页面的行为(例如将表单提交地址改为攻击者服务器)。
      • 子域安全问题: 即使根域名相同(site.com),sub1.site.comsub2.site.com 也被视为不同源。这在大型网站或多租户系统中很常见。如果允许自由访问,托管在 untrusted-tenant.site.com 上的恶意代码就可能试图窃取 secure.site.com 的 Cookie 或 DOM 数据。
      • 公共 CDN 或第三方库风险: 很多网站使用公共 CDN (如 cdnjs.com) 来加载第三方库。如果这些库有漏洞或被篡改,攻击者可能会利用它们来试图访问主站 yoursite.com 的 DOM 或数据。不同源策略限制了这种行为。
  3. 端口不同 (Port) - 例如 site.com:80 vs site.com:8080

    • 安全问题:服务隔离、内部服务暴露、权限旁路

      • 服务隔离: 同一个主机上可能运行着多个不同的 web 服务(例如,主应用在 80 端口,管理后台在 8080 端口,测试环境在 3000 端口)。它们服务于不同的目的,有不同的安全等级。如果一个高权限服务(如管理后台)的 Cookie 可以被运行在另一个端口(如测试环境)的脚本随意访问,就可能导致权限提升攻击。
      • 开发/测试环境暴露: 开发人员经常在非标准端口(如 localhost:3000)运行前端,同时后端的 API 可能运行在 localhost:8080。如果不检查端口,那么浏览器在访问 localhost:3000 加载的前端页面时,该页面的脚本就能完全访问 localhost:8080 的 API 响应(可能包含敏感数据或调试信息),这可能会在无意中将内部信息暴露给前端代码。
      • 绕过防火墙/策略: 内部网络的安全策略可能只允许访问主服务的标准端口(80/443),而封锁其他端口。如果浏览器允许前端脚本自由访问服务器上的其他开放端口,攻击者可能利用恶意网页探测和攻击这些内部服务,尽管主域名是受信任的。
相关推荐
寻星探路17 分钟前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
王达舒199417 分钟前
HTTP vs HTTPS: 终极解析,保护你的数据究竟有多重要?
网络协议·http·https
朱皮皮呀19 分钟前
HTTPS的工作过程
网络协议·http·https
Binary-Jeff23 分钟前
一文读懂 HTTPS 协议及其工作流程
网络协议·web安全·http·https
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端