内容安全策略 nonce 不适用于事件处理程序属性
Posted
技术标签:
【中文标题】内容安全策略 nonce 不适用于事件处理程序属性【英文标题】:Content Security Policy nonce does not apply to event handler attributes 【发布时间】:2019-10-17 09:15:55 【问题描述】:我正在将 CSP 标头添加到一个网站,该网站还有很长的路要走才能采用严格的政策。有很多内联脚本,所以我使用 nonce- 来允许特定的内联脚本。我发现它不适用于带有 src 的脚本标签的 onload
属性。这是一个例子:
// header:
Content-Security-Policy: script-src self https: 'nonce-d3adbe3fed'
<script async defer src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js" nonce="d3adbe3fed" onload="console.log('onload', _.VERSION)"></script>
完整的工作演示在https://brave-pasteur-0d438b.netlify.com/
Chrome 出现以下错误:
Refused to execute inline event handler because it violates the following Content Security Policy directive: "script-src self https: 'nonce-d3adbe3fed'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
该消息表明应该可以使用 nonce 启用内联事件处理程序,但据我所知,nonce 仅适用于内联脚本。
这只是一个演示,但用例是加载跟踪库的异步/延迟跟踪脚本,然后在 onload
处理程序中对加载的库进行跟踪调用。
是否可以在onload
或其他事件处理程序属性上使用随机数,或者我需要更改我的实现吗?使用script-src 'unsafe-inline'
或script-src-attr 'unsafe-inline'
不是一种选择,因为这些是我特别试图解决的漏洞。并且将onload
处理程序的内容放入脚本标记之后的单独脚本中也不是一种选择,因为脚本是async deferred
,并且需要保持这种方式。
【问题讨论】:
错误信息具有误导性。请参阅github.com/w3c/webappsec/issues/468 并查看***.com/questions/50842033/… 的评论。尽管该错误消息似乎暗示了什么,但在 CSP2 和当前浏览器中,只有元素内容是“不可确定的”——而事件处理程序属性则不是。 但另请参阅***.com/a/44609372/441757 的答案。 CSP3 添加了一个新的unsafe-hashes
表达式以允许特定的内联脚本/样式。见w3c.github.io/webappsec-csp/#unsafe-hashes-usage。有关详细信息,请参阅docs.google.com/document/d/… 上的解释器:'unsafe-hashes'、'unsafe-inline-attributes' 和 CSP 指令版本控制文档。但unsafe-hashes
功能尚未在除 Chrome 之外的任何浏览器中提供:chromestatus.com/feature/5867082285580288
请注意:CSP2 规范中的语言更清楚地说明了哪些 nonce 可以和不能一起使用;它有一个明确标题为 Nonce 用于脚本元素 w3.org/TR/CSP2/#script-src-nonce-usage 的特定部分,但没有类似的部分标题为“事件处理程序的 Nonce 用法”(或类似)。 (一般来说,当试图弄清楚 CSP 要求和行为时,我经常发现(旧的)w3.org/TR/CSP2 规范中的语言以比当前规范更加开发人员友好(相对于浏览器实施者友好)的方式声明它们在w3c.github.io/webappsec-csp 确实)
对未来读者的另一个注意事项:哈希值也不适用于事件处理程序。因此,允许特定内联事件处理程序的唯一方法是允许所有事件处理程序。在我看来,这是当前 CSP 实施的重大失败。
使哈希值在事件处理程序上起作用是新的 CSP3 unsafe-hashes
表达式的用途。尽管正如我在之前的评论中提到的,unsafe-hashes
支持尚未在除 Chrome chromestatus.com/feature/5867082285580288 之外的任何浏览器中提供,但这种情况下的失败至少不是由于规范作者忽略为其定义机制——相反,其他浏览器项目未能优先考虑实施它。也许部分原因是,他们只是没有听到足够多的开发人员认为他们应该优先考虑它。
【参考方案1】:
如果有办法在内联处理程序上使用nonce
,我将接受一个证明它的答案。不幸的是,在撰写本文时,我认为没有。
作为一种解决方法,以下脚本表现出与具有 async/defer 和 onload 处理程序的脚本相同的行为和时序,同时满足指定的 CSP 策略:
<script nonce="d3adbe3fed">
let s = document.createElement('script');
s.src = 'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js';
s.onload = () => console.log(_.VERSION);
document.documentElement.appendChild(s);
</script>
当然,长期的解决方案是完全消除内联脚本,但在短期内这并不总是可行的,最好尽快实施更宽松的政策,而不是推迟它并且没有 CSP完全没有。
【讨论】:
以上是关于内容安全策略 nonce 不适用于事件处理程序属性的主要内容,如果未能解决你的问题,请参考以下文章
内容安全策略“数据”不适用于 Chrome 28 中的 base64 图像
带有内容安全策略的 Angular 12 CSS 优化内联事件处理程序
href 标记中的内容安全策略错误,但在内联事件处理程序上工作正常