具有内容安全策略的 Angular 12 CSS 优化内联事件处理程序

Ale*_*oss 19 angular-cli angular angular-devkit

升级到 Angular 12 后,我的内容安全策略阻止了正确加载样式。

Angular 12 devkit 似乎向 index.html 中的 CSS 包引用添加了一个新的内联事件处理程序,示例如下。

<link rel="stylesheet" href="styles.5951e4ca367b697db091.css" crossorigin="anonymous" integrity="sha384-2031E8+oC87S0N7NzRGcF8fqx777KEJOgQ3KcUN4aX6xsR3BVaV5sh4fibR5joOc" media="print" onload="this.media='all'">

Run Code Online (Sandbox Code Playgroud)

错误

Refused to execute inline event handler because it violates the following Content Security Policy directive...
Run Code Online (Sandbox Code Playgroud)

这似乎与此 RFC 相关:https : //github.com/angular/angular-cli/issues/18730但我找不到有关如何使用严格(没有“不安全内联”)的更多信息) CSP。

小智 25

Angular 12 升级后我遇到了同样的问题。

我的解决方案是将工作区选项优化“inlineCritical”设置为 false。Angular 12 中的 inlineCritical 选项已更改为默认 true 以改进 First Contentful Paint,请参阅https://angular.io/guide/workspace-config#styles-optimization-options

这是一个示例工作区配置

"project": {
  "architect": {
    "build": {
      "configurations": {
        "production": {
          "optimization": {
            "scripts": true,
            "styles": {
              "minify": true,
              "inlineCritical": false
            },
            "fonts": true
          }
        }
      }
    }
  }
},
Run Code Online (Sandbox Code Playgroud)

  • 我禁用此选项的问题是因为使用 Express 的 Angular Universal 有一个单独的选项,例如 `ngExpressEngine({ bootstrap: AppServerModule, inlineCriticalCss: false });` 该选项的文档仍然说它默认为 false,但这似乎不是就这样吧。 (2认同)
  • 如果他们真正定义了“关键”的含义,那就太好了。例如,我有一些对于预加载“/assets/preload/preload.css”至关重要的 css,那么为什么不将其内联呢? (2认同)

Joh*_*non 7

注意力!答案已更新

更新答案(2021 年 7 月 16 日)

下面发布的原始解决方案破坏了 Safari (MacOS),因此我们不得不回滚并禁用optimization.styles.inlineCritical.

此外,正如下面的masterfloda所评论的,在大多数情况下,如果不是所有情况,选择应该是安全性而不是性能。我最初的想法是利用 ( unsafe-hashes)会很困难,但我还没有对此进行彻底的 InfoSec 风险评分。

Angular repo - #20864上有一张票。我建议您暂时禁用optimization.styles.inlineCritical并喜欢并订阅该问题。


原始答案(2021 年 6 月 9 日)

是的,这个问题是由 Angular v12 的样式优化选项( inlineCritical: true)引入的,它onload向主样式表的链接标记添加了一个事件处理程序,如下所示:

<link rel="stylesheet" href="styles.<hash>.css" media="all" onload="this.media='all'">

无需在CSP中禁用inlineCritical或启用即可解决'unsafe-inline',如下所示:

  • 散列onload处理程序的内容:this.media='all'
  • 报告 URI有一个方便的工具:Script And Style Hasher
  • 将哈希添加到script-srcCSP 中的指令
  • 对于 Chrome(但不是 FF),您还需要添加'unsafe-hashes'script-src指令中,否则它会在控制台中通过以下日志阻止:请注意,哈希不适用于事件处理程序、样式属性和 javascript: 导航,除非'不安全- hashes 关键字存在

  • 我已经对不安全哈希的使用进行了风险评分。虽然攻击的影响很大(例如,由于泄露用户会话令牌而导致会话劫持),但只要您有足够的 XSS 保护(例如 CSP 没有“不安全内联”、HTML 结束码 + 渲染上的清理),可能性就很低)。XSS 注入漏洞必须存在并被攻击者发现,然后他们才能利用不安全哈希。 (3认同)
  • 出于安全原因,我认为这不是一个好的答案:我宁愿不针对 First Contentful Paint 进行优化,也不愿在我的 CSP 中允许“不安全哈希”。 (2认同)