浏览器为什么选择了如今的同源策略

2022-03-26 17:48:16 +08:00
 wheelg

浏览器会禁止下面的类似操作

a.com中的 js 向b.com/api发送了请求,根据同源策略,这样的跨域请求会向b.com 发送一个 OPTIONS 预检请求,如果服务器返回的 Access-Allow-Origins 中不包含a.com ,那么此次请求会被浏览器拒绝,a.com中的 js 拿不到请求返回的数据。

这样的行为如果发生在本地应用程序例如 postman 中时,是可以拿到正常的请求数据的,因为 postman 没有同源策略,不会限制发送任何请求,那么为什么浏览器要对此做出限制?

网上的大部分解释是,浏览器在向某个域名发起请求时,会携带上对应的网站 cookie ,如果用户登录了b.com,又打开了a.coma.comb.com/api发送的请求会带上b.com的 cookie ,会让b.com服务器认为是用户本人在操作,导致恶意攻击的发生。

那么为什么浏览器不能分辨是哪个网站发起的请求呢?为什么浏览器不能在检测到是a.com发出的请求时,不携带b.com网站保存的 cookie 呢?这样不就能同样规避此类攻击吗?就如同在浏览器直接输入 api 网址那样拿到返回结果不行吗?

我的理解是,浏览器厂商不能这样做,因为许多广告厂商需要在网站中嵌入第三方 cookie ,这样才能通过第三方 cookie 来确定同一用户,方便广告投放,但是这个说法也显然站不住脚,因为如今许多浏览器厂商都在主动禁止第三方 cookie ,那么这个同源策略到底保护的是什么呢?

7745 次点击
所在节点    程序员
72 条回复
duke807
2022-03-26 23:08:57 +08:00
大家可以查一下 cors proxy ,不允許跨域訪問的資源用第三方 cors proxy 中轉一下就可以了,所以感覺 cors 貌似意義有限,更多的是帶來麻煩
BeautifulSoap
2022-03-26 23:17:18 +08:00
@wheelg 嗯?“如果黑客已经在你的网站里插入了恶意代码,他完全可以直接访问他自己的服务器,只需要用 cors 跨域就可以了” 我有点好奇,你可不可以举一个具体的例子讲讲,黑客怎样才能做到? 莫非你说的是在未正确配置 CSP 的时候?
nuk
2022-03-27 01:07:43 +08:00
@rekulas 这里只是举个例子说明就算没有 cookie 的情况也是很危险的,重启的 api 这个例子举得不好,可以换成需要获取 token 再调用的 api
jim9606
2022-03-27 01:25:39 +08:00
看这个知乎回答是不是解答你的疑惑吧。我的理解是浏览器并不想破坏“跨域表单”这个用法。

为什么跨域的 post 请求区分为简单请求和非简单请求和 content-type 相关? - 贺师俊的回答 - 知乎
https://www.zhihu.com/question/268998684/answer/344949204

至于第三方 Cookies 是另一个话题。以下为个人见解可能有错:拦截第三方 cookies=跨站(cross-site)请求的响应的 Set-Cookie 头会被忽略+SameSite 属性不能为 None 。
wazggcd
2022-03-27 01:32:17 +08:00
@nuk img 的 src 不受同源策略影响
IvanLi127
2022-03-27 01:32:49 +08:00
你说:
那么为什么浏览器不能分辨是哪个网站发起的请求呢?为什么浏览器不能在检测到是 a.com 发出的请求时,不携带 b.com 网站保存的 cookie 呢?这样不就能同样规避此类攻击吗?就如同在浏览器直接输入 api 网址那样拿到返回结果不行吗?

如果我前后端分离,api 的域名和 web 域名不同,不就 gg 了?而且你这种限制已经比浏览器自带的限制还大,而且静默吞 Error 。很恶心的。。。。
Al0rid4l
2022-03-27 03:33:35 +08:00
"为什么浏览器不能在检测到是 a.com 发出的请求时,不携带 b.com 网站保存的 cookie 呢?"
仅针对这一句回答, 有没有可能, 我是说可能, b.com 其实希望接受这个 cookie 呢? 你这个方案相当于假设了 b.com 不需要这个 cookie, 直接剥夺了 b.com 的选择权, 而浏览器给了 b.com 这样的选择权
很多人认为同源策略的目的是为了防止某类攻击, 是为了保护什么, 但是同源策略本身的意图真的是这样吗? 还是你们一厢情愿地这么认为? 同源策略仅仅是浏览器框架下为 a.comb.com 提供了一套交互的规则, a.com 索取资源需要在这个规则下完成, 而 b.com 有权利选择是否给予, 当然这一切都是仅限于浏览器框架内. 同源策略保护了什么吗? 当然的确也在某些方面提供了保护, 但那是它全部的设计意图吗? 把同源策略的目的理解为防范攻击未免过于一厢情愿和狭隘了.
毕竟如果你真的想要不经过 b.com 的同意获取资源, 那大可以写爬虫, 但这已经脱离了浏览器框架内了, 不是同源策略要考虑的问题, 而在浏览器内, 同源策略保护了 b.com 的同时, 也给 b.com 留下了选择的权利, 而你的方案里, 显然没有给 b.com 提供任何选择的机会, 充满了独裁意味
而如果考虑有没有必要给 b.com 这样的选择, 那当然是有必要的, 当你的业务足够多, 需要多个子域名区分, 同时又希望它们之前能够有一些资源上的交互, 并且仅限于自己公司下几个域名之间而不想给其他域名获取你的资源, 那就有必要了
duke807
2022-03-27 05:05:26 +08:00
@Al0rid4l
如果我的網站業務足夠多,有多個域名,我每個域名都使用相似的 API 接口,通過 API 接口傳參數就可以實現資源上的交互啊,為啥一定要用 cookie 呢?

如果是靜態資源,我服務器可以檢測用戶從哪個頁面發起的請求( refer 字段),從而選擇是否給予服務

cors 的功能本來就應該是服務器端負責實現,不應該放到客戶端實現
duke807
2022-03-27 05:08:38 +08:00
服務器端負責實現的例子:網上經常能看到一些圖片壞掉,圖片內容變成了提示:只能在 xxx 網站觀看、不允許盜鏈。
acthtml
2022-03-27 09:56:50 +08:00
同源策略是个有东西,网景公司发明的。
一开始只是限制 cookie ,后面才限制 api ,主要是防止 XSS 。
thtznet
2022-03-27 10:26:51 +08:00
我的简单理解:浏览器厂商甩锅给网站运维的一个单方面政策
awolf
2022-03-27 10:39:15 +08:00
@Biwood ajax 请求怎么分辨?
awolf
2022-03-27 10:40:43 +08:00
@Al0rid4l 我觉得就是这样,楼主估计只考虑 防御,没考虑反向,接受的情况
rekulas
2022-03-27 11:36:18 +08:00
@musi 协议倒并没有误解,不过我们理解的漏洞情况不一样吧,我理解的是大部分情况下用户构造一个 url 即可以发送非法指令,这种情况同源策略确实无法阻止,你理解的是即使 get 也需要多步交互才能构造正确的指令,这种情况同源有效,只能说都不算错吧只是需要考虑场景,毕竟 2 种情况都存在
wheelg
2022-03-27 11:58:45 +08:00
看了各位的回答后,我的理解是这样的:

浏览器在设计之初并没有一个很好的身份认证手段,于是采用了 cookie 用作身份认证,为了鉴定用户身份,浏览器不得不每次发送请求时都带上请求网站的 cookie ,因此为了考虑兼容性,不能阻止`a.com`向`b.com`发送请求时带上`b.com`的 cookie 。

所以为了避免恶意网站利用这个 cookie ,对于非同源请求,浏览器选择了先向服务器询问`a.com`是不是可信任的( OPTIONS 预检),得到确认后才会向服务器发送真正的请求,也就是同源策略。

如今大部分本地应用采用的是 jwt 方式保存登录信息,因此也就避免了浏览器 cookie 的漏洞,所以不需要同源策略,虽然现在的网页也可以使用 jwt 方式认证,但是为了兼容性,浏览器依然需要使用原有的 cookie 发送策略,才会有同源策略这一限制。

那么以后会不会出现某种新的浏览器 API ,使用此 API 时可以抛弃原有的 cookie 策略,允许开发者自由访问其他域名的请求呢?
liaohongxing
2022-03-27 12:00:23 +08:00
假如你登陆了工商银行的网页 A ,网页 A 给你浏览器写了个登录 cookie , 里面有个转账接口 POST 方法 http://www.ccb.com/cn/transfer/ , 需要 POST 内容 {"uid": "我的账户 UID", "money": 100} , 发起这个 POST 需要携带 Cookie, 如果我做个网页 B ,如果没有任何跨域限制,并且携带 cookie ,你访问网页 B ,网页 B 执行这个跨域 POST 方法,这个 POST 就会成功, 从而实现无缝转账 ,直接清空你的银行账户 , 这个可以衍生到很多其他方面。用你名义发帖,用你名义发邮件等等。

想要阻止这种方案,两个简单方法:
1. 网页 A 的请求圈在自己网站内(也就是域名内)。除非网站 B 某些接口主动加 CORS, 但是开了 CORS 对网站 B 又不安全 ,网站 B 有 Origin 字段, 限制允许的域名
2. 去除 Cookie, 假如没有跨域限制,网页 B 能访问接口, 但是浏览器去除了 Cookie, 访问网页 A 的接口时会提示 “未登录” ,但是某些 java 应用喜欢在 URL 里用 JSESSION 传递, 所以去除 Cookie 不一定有效 。所以需要和限制域名一起使用 。
Biwood
2022-03-27 12:09:33 +08:00
好吧今天重读了一下才大概理解 OP 的意思。

网页应用和系统本地应用最大的一个区别就是,本地应用不存在“跨域资源共用”这件事情,比如你打开微信,你觉得微信里面会引用迅雷提供的某个二进制代码文件吗?就算有引用,多半也还是基于网页形式,这就是网页的特殊性。在网页上这种情况却从一开始就是存在的,也正因为这种极高的复用性,才使得每个网页可以做到只有几 KB 的大小,而不是每个域名下的网页都要重新下载 CSS/JS/图片等等。

而因为这种高度的互相引用能力,必然会导致出现一些跨域攻击的漏洞 XSS/CSRF 等,正因为及其不安全,所以才有了严格的同源策略。

之所以成为现在这套策略,相信 W3C 以及各个浏览器厂家和互联网大厂都经过推理的,这里面有一套严密的逻辑,你既要保证各个域的资源能相互引用,又要保证引用的时候不被恶意利用。
3dwelcome
2022-03-27 12:36:34 +08:00
同源限制的是,你网站 ajax ,去调用别的网站 api 的能力。
比如我写的 gitview 网页工具,需要请求 www.github.com 的 get 方法。但这个请求没经过 github 的审批,没把我的域名放进白名单,就被浏览器代为阻止了。
这个权限 github 后台服务器可以控制,跨域也算是一种后台对访问域名的授权吧。
duke807
2022-03-27 13:36:16 +08:00
@3dwelcome
如果瀏覽器沒有 cors 機制
github 服務器端可以判斷來源,然後決定是否允許本次的 api 調用,見 #49 樓舉的例子

另我在 #41 樓有提到,目前在瀏覽器端實施的 cors 機制很容易繞過:不允許跨域訪問的資源用第三方 cors proxy 中轉一下就可以了,譬如你要訪問的連接改為 github.com/xxx/yyy 改為 proxy.zzz/github.com/xxx/yyy 就可以訪問了
安全上根本得不到保護
duke807
2022-03-27 13:43:33 +08:00
我懷疑這麼設計主要目的是為了降低跨域引發的 DDoS 攻擊的烈度

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/843069

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX