杂谈

一些零碎的记录和思考 @ 2024

#记录 #积累

写一些不能单独成文或者不好分类的文字。

2024-09


[09-12] 关于 iframe 的同源策略限制和 Content-Security-Policy

今天遇到一个用户提的 oncall,用户在我们的系统底下嵌入了一个 iframe,iframe 内容是用户公司自建的页面。用户的诉求是从子页面拿到顶层页面 (iframe 宿主) 的 URL,然后遇到了跨域问题,用户提问是否可以配置 iframe 属性或者配置 CSP 绕过,把我问住了。

我们来尝试复现一下用户的场景,用户是这样做的:

http://localhost:8080

<html>
  <head>
    <title>Parent Page</title>
  </head>
  <body>
    <iframe src="http://localhost:8081/" />
  </body>
</html>

http://localhost:8081

<html>
  <head>
    <title>Child Page</title>
  </head>
  <body>
    <script>
      console.log(window.top.location.href);
    </script>
  </body>
</html>

不出意外就要出意外地报错了:

Uncaught SecurityError: Failed to read a named property 'href' from 'Location': Blocked a frame with origin "http://localhost:8081" from accessing a cross-origin frame.

很明显问题是出在了 window.top.location.href 的读取(跨源访问)被浏览器的同源安全策略拦截了。根据 MDN 上对 浏览器同源策略 的描述,大部分属性的跨源访问是只读的,唯独对 Location 对象的 href 属性是只写的(实际上大部分的 “跨源读操作” 一般是不被允许的):

同样地从父页面访问子页面的 window 和 Location 对象也是受限的,这种情况下设置 Access-Control-Allow-Origin 也不好使。一般来说这种情况最好的办法是直接通过 iframe src 设置 URL query 来传递父页面 URL,或者需要传递复杂信息的时候使用 window.postMessage.

问题其实到这里解决了,但是用户一开始提出的方案 “配置 iframe 属性或者配置 CSP 绕过” 是否有可行性呢。

iframe sandbox

先说说是否能配置 iframe 的属性来绕过一些浏览器的安全限制。iframe 有一个 sandbox 属性,允许开发者限制 iframe 中页面的行为,如执行 JS、下载文件、提交表单、弹窗等,也可以强制浏览器将一个同源的 iframe 页面视为非同源页面。

但实际上我们直接使用 <iframe src="xxx" /> 这样来嵌入一个 iframe 的时候,不会应用任何限制,所以其实没有必要特地指定属性,对 iframe 和浏览器来说同源就是同源,非同源就是非同源,指定 sandboxallow-scriptsallow-same-origin 限制并不能改变这一点。

Content Security Policy

再说说内容安全策略 (Content Security Policy, CSP)。 其实今天之前我也不知道 CSP 具体有啥用,所以用户提到这个的时候我也有些懵逼。

简而言之,CSP 主要是控制浏览器可以为该页面获取哪些资源,一般我们可以在返回的响应头或者 meta 中设置 CSP:

<meta
  http-equiv="Content-Security-Policy"
  content="default-src 'self'; img-src https://*; child-src 'none';" />

CSP 通过特定的 DSL 来描述访问限制的策略,格式是 key-src domain1 [domain2] ... ;,更多示例可以看 MDN.

  • 必须包含一个 default-src
    • default-src 'self' 表示当前页面引用的所有内容,都只能来自当前页面所在的域名(子域名也不行)
    • 可以使用通配符,指定一个白名单,信任除当前页面域名外的某个域名及其子域名:default-src 'self' *.trusted.com
  • 通过 img-src 限制图片引用、media-src 限制媒体文件引用、script-src 限制脚本引用:
    • default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
  • 利用 CSP 也可以用来做其它的限制,例如强制使用来自 SSL 的资源:default-src https://xxx.com

CSP 还可以设置为警告模式,并且还能够通过 report-uri 来将违反 CSP 的行为报告给服务器。

总之 CSP 是个比较冷门的功能,可以用 CSP 来减少 XSS 攻击的发生。同样,默认不设置 CSP 的时候,其实也是采取了最宽松的引用限制的。所以它能解决用户的问题吗?答案也是不能。