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

公众号:小博的前端笔记

同源策略(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),而封锁其他端口。如果浏览器允许前端脚本自由访问服务器上的其他开放端口,攻击者可能利用恶意网页探测和攻击这些内部服务,尽管主域名是受信任的。
相关推荐
OEC小胖胖4 小时前
去中心化身份:2025年Web3身份验证系统开发实践
前端·web3·去中心化·区块链
vvilkim4 小时前
Electron 进程间通信(IPC)深度优化指南
前端·javascript·electron
ai小鬼头6 小时前
百度秒搭发布:无代码编程如何让普通人轻松打造AI应用?
前端·后端·github
漂流瓶jz6 小时前
清除浮动/避开margin折叠:前端CSS中BFC的特点与限制
前端·css·面试
前端 贾公子6 小时前
在移动端使用 Tailwind CSS (uniapp)
前端·uni-app
散步去海边6 小时前
Cursor 进阶使用教程
前端·ai编程·cursor
清幽竹客6 小时前
vue-30(理解 Nuxt.js 目录结构)
前端·javascript·vue.js
weiweiweb8887 小时前
cesium加载Draco几何压缩数据
前端·javascript·vue.js
幼儿园技术家7 小时前
微信小店与微信小程序简单集成指南
前端
我不吃饼干9 天前
鸽了六年的某大厂面试题:你会手写一个模板引擎吗?
前端·javascript·面试