同源策略:允许写入吗?

21

我对MDN关于同源策略的描述有些困惑。

他们说:

通常允许跨域写入....

通常允许跨域嵌入....

通常不允许跨域读取...

我理解第二个项目允许标准嵌入跨域内容(例如来自CDN的内容)到网站中:

  • <script src="...">
  • <link rel="stylesheet" href="...">

但是,“允许写入”和“不允许读取”是什么意思? “写入”是否指我的网站向另一个网站写入,还是反向操作?同样,“读取”指的是哪个方向?非常感谢提供一些示例。


写入通常表示HTTP请求。这意味着可以是双向的。 - SLaks
1
跨域写入是指像向不同域名的<form>提交一样的操作。这些操作被浏览器允许,也是浏览器本身无法解决CSRF问题的原因。 - Pointy
1
值得记住的是,MDN是由社区协同编辑的。我不认为我会在那里使用“写作”这个词。它会带来更多的困惑,而不是减轻困扰。 - T.J. Crowder
@Pointy 当从另一个域发送的表单数据读取时,有必要检查不可预测的CSRF令牌吗?编辑:我想这是有道理的,以避免从恶意来源读取。我实际上还没有实现这样的通信,所以不确定它是如何完成的/我的问题是否有意义。 - Magnus
CSRF (跨站请求伪造)令牌可以是表单的显式部分,也可以添加到XHR请求标头中。无论哪种情况,都不应该让第三方域从您的网站读取暴露令牌的页面内容。通常使用某些安全值,每个用户会话唯一。 - Pointy
2个回答

12

MDN给出了什么是“writes”的示例:

示例包括链接、重定向和表单提交。某些很少使用的HTTP请求需要preflight

因此,例如我的网站example.com可以有以下内容:

<form action="https://google.com/search" id="kittens-form" target="_blank">
<input type="hidden" name="q" value="kittens">
</form>

...然后做这个:

document.getElementById("kittens-form").submit();

在 jsFiddle 上的示例

(在这种特定情况下,因为我有target="_blank",我必须响应用户操作才能打开新窗口,否则会触发弹出窗口拦截器。但如果我不打开新窗口,我可以随时使用它。)

同样的,“read”指的是什么方向?

他们谈论运行在 A 点源的代码从 B 点源中读取信息。所以,我的恶意 example.com 网站不能在没有您的银行明确允许的情况下通过CORS从您的银行网站读取信息(这样我就无法窃取您的银行账户信息,因为您的银行会话可能正在运行...)。

更多详细信息,请参见此问题的答案:Same origin Policy and CORS (Cross-origin resource sharing)


谢谢T.J.但是,如果我能写,难道我就不能读吗?我的意思是,我可以将我的恶意脚本编写到银行的DOM中,然后当它在他们那里执行时,我的脚本会将所有我想要的信息发送给我。 - Magnus
2
@Magnus - 将信息发送到网站并不意味着该网站会运行您的代码。某些随机不受信任的来源确实可以向网站提交代码以供运行,但您的银行网站可能不会这样做。或者说,它不会再这样做太久了...;-) - T.J. Crowder
4
@Magnus - "Link" 的意思是 <a href="...">...</a>,当提到 link 元素时,需要更具体的描述而不仅仅是使用 "link" 这个词。但在这两种情况下,信息(URL 和可能的查询字符串参数)都会被发送到目标站点,目标站点可以使用它们。因此,在某种程度上,这是向目标站点“写入”信息,目标站点可以“读取”该信息。 - T.J. Crowder
3
@Magnus - 你想的是浏览器窗口之间的通信。这不是 MDN 所讨论的内容。它谈论的是浏览器托管的 JavaScript 代码将信息发送到站点的 服务器。(而且,除非两个文档都使用 document.domain,否则你不能在浏览器中修改从不同来源加载的文档的 DOM,即使是在相当有限的情况下也不行。) - T.J. Crowder
1
啊,“写入”在这里使用是一个非常糟糕的术语,正如你上面所指出的那样。我的第一反应是他们可能是指我可以获取另一个窗口对象:const newWin = window.open('https://www.google.com', 'windowName');,然后按照我想要的方式写入它的DOM。但我知道这是不可能的,因此感到困惑:) 再次感谢。 - Magnus
显示剩余2条评论

2
我在挣扎了半个小时之后,终于把这句话 this saying 解释清楚了:
  • 通常允许跨域写入……
  • 通常允许跨域嵌入……
  • 通常不允许跨域读取……

它将同源问题分类为三种类型,但是根据是否与服务器交互,我更喜欢将同源策略分为两种类型:
  1. 在浏览器内从originB读取originA的已加载资源
  2. 在浏览器内从originB请求originA的远程资源
第一种对应于上述引文中的“跨域读取”案例,第二种对应于“跨域写入”和“跨域嵌入”。 (因此,是的,您会发现“写入”和“嵌入”实际上都意味着从远程服务器请求资源,而不是直接从本地读取)
第一种类型很容易处理:浏览器肯定会阻止它。 因此,网站A的javascript片段无法读取由网站B设置的cookie-从而确保了我们Web账户的安全性。
第二种类型有些复杂,有很多情况下一个origin向另一个origin发起请求,就目前而言,我能列出以下几种情况:
  1. 链接到不同网站的 <a href=... 标签
  2. 向不同网站 发送(写入)数据的 <form action=... method="POST"> 标签
  3. 从不同网站加载 CSS 样式并将其 嵌入原始页面的 <link rel="stylesheet" href="…"> 标签
  4. 加载其他地方的图片并将其 嵌入原始页面的 <img> 标签
  5. 加载其他地方的 JavaScript 代码片段并将其 嵌入原始页面的 <script> 标签
  6. XMLHttpRequest AJAX 请求
  7. Web 字体(用于跨域字体在 CSS 中的 @font-face 使用)
  8. WebGL 纹理。
  9. 使用 drawImage() 将图像/视频帧绘制到画布上。
  10. 从图像中创建 CSS 形状。
其中,浏览器允许1-5个情况,同时阻止6-10个情况,将来可能会有11、12等情况被浏览器阻止,这个Mozilla页面可能是跟踪未来新的阻止情况的更好地方。
最初发布于:

https://cifer76.github.io/posts/same-origin-policy/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接