通过嵌入标记加载的 PDF 被 CSP 中的 frame-src 指令阻止

PDF loaded via embed tag blocked by frame-src directive in CSP

我在沙箱中制作了一个最小可重现的示例,但事实证明沙箱会阻止插件,因此我们只需要按照问题的描述进行操作即可:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'self'; child-src 'none'; object-src https://www.w3.org; connect-src *;"
    />
    <title>PDF CSP Violation Example</title>
  </head>
  <body>
    <embed
      type="application/pdf"
      src="https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    />
  </body>
</html>

鉴于上述 HTML,PDF 将在 Firefox 和 Safari 的 PDF 查看器插件中加载,但不会在 Google Chrome 或 Microsoft Edge 中加载。最后两个浏览器会抱怨它违反了 frame-src 指令,该指令依赖于 child-src。我无法找到任何解释此违规行为的内容,因为根据描述 frame-src 用于 iframe 元素,而 object-src 处理 embed 标签。我假设潜在的问题与 Chromium 及其显示 PDF 的方式有关,因为 Chrome 和 Edge 都构建在 Chromium 之上。

我的问题是,是否有两个解释为什么这违反了指令,或者这可能是 Chromium 中的错误?

Safari 和 Firefox 完全按照 CSP 规范运行 - <embed> / <object> 标签包含在 object-src 指令中。

基于 Chromium 的浏览器 (since Chrome 76) 的行为与 CSP 规范相矛盾:它们首先通过 object-src 指令检查 <embed> / <object> 标签的来源,然后之后通过 frame-src(或通过 child-srcdefault-src 进行回退检查)。
这看起来不像 Chrome 错误,因为在 embedding png/jpg 图像的情况下, Chrome 仅使用 object-src 指令。但是如果你嵌入一个像 svg/pdf/mp4 这样的“复杂”对象 - Chrome 通过 frame-src.

执行第二次检查

很可能,Chrome“知道”使用 <embed> / <object> 标签的不安全性。解决方案是不使用这些标签,而是使用 <iframe> 代替。

关于 <embed> / <object> 标签的不安全和过时

基于插件技术的 <embed> / <object> 标签 - 用户必须安装第三方插件才能呈现浏览器无法理解的内容。
这些标签不支持现代安全机制(例如 allow=csp=sandbox=属性)因此它们已被废弃,取而代之的是 <iframe>,参见 From object to iframe — other embedding technologies.

大多数现代浏览器 have deprecated and removed support 用于浏览器插件,因此如果您希望您的站点在普通用户的浏览器上可操作,那么依赖 <embed> 通常是不明智的。

<object> 元素主要用于嵌入 Adob​​e Flash,即 insecure and outdated
由于其固有的问题以及对 Flash 的不支持,Adobe 宣布他们将在 2020 年底停止支持它。截至 2020 年 1 月,大多数浏览器默认阻止 Flash 内容,到 12 月 31 日到 2020 年,所有浏览器都将完全删除所有 Flash 功能。在该日期之后将无法访问任何现有的 Flash 内容。

为了保持一定的向后兼容性,浏览器实现了自己的内置插件来呈现某种嵌入内容。这就是为什么您仍然可以使用 <embed> / <object>.
嵌入 PDF/VIDEO/AUDIO/SVG 但在某些情况下,浏览器会强制将 <object> 替换为 <iframe> - 只需使用以下内容创建页面:

<object width="425" height="344">
  <param name="movie" value="https://www.youtube.com/v/9Ey_oeLlM9I&hl=en&fs=1&cc_load_policy=1"></param>
  <param name="allowFullScreen" value="true"></param>
  <embed src="https://www.youtube.com/v/9Ey_oeLlM9I&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed>
</object>

并检查真实的 html 代码 - <object><embed> 标签被替换为 <iframe> 一个。某些版本的 Firefox 在控制台中会出现这样的警告:

Replace old Flash Player-based YouTube embeds by their new HTML5 counterparts.
Params were not supported by iframe embedds and were converted.
Please update the page code to use an iframe instead of embed/object, if possible.