26

我正在尝试使用MathJax作为我们使用非常严格的内容安全策略 (CSP)的 Web 应用程序的一部分。问题是 MathJax 被编码为使用eval()[确切地说,以Function()] 的形式,默认情况下 CSP 认为它不安全。

我目前正在使用以下 CSP 标头:

X-Content-Security-Policy: allow 'self'; img-src *; media-src *; frame-src *; font-src *; frame-ancestors 'none'; style-src *; report-uri '/:save-csp-violation';

这会导致 MathJax 2.0 代码失败,因为它使用Function(). 我试图只允许Function()位于 path 下同一原点内的 MathJax 的 unsafe-eval (即)/:static/math/。为此,我尝试添加

unsafe-eval '/:static/math/*'

使完整的标题看起来像

X-Content-Security-Policy: allow 'self'; img-src *; media-src *; frame-src *; font-src *; frame-ancestors 'none'; style-src *; report-uri '/:save-csp-violation'; unsafe-eval '/:static/math/*'

但我仍然无法 Firefox 13.0 运行代码。我收到一条发给 Firefox Web 控制台(位于工具 - Web 开发人员)的错误消息:

[10:09:59.072] call to Function() blocked by CSP @ http://localhost:8080/:static/math/2.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML:29

但是,我没有收到“report-uri”的 CSP 报告。(如您所见,我目前正在通过没有 SSL 的自定义 localhost 端口运行测试,以防万一。前面的冒号static不是错字,我保留所有以冒号开头的路径部分供内部使用应用程序,所有用户内容都可以自由定义其他 URL。)

我对unsafe-eval属性的使用是不正确的,还是不可能只对“自我”的子集允许不安全评估?目的是只允许 unsafe-eval 用于相同的源路径前缀/:static/math,严格的 CSP JS 代码执行 ' self' 并且不允许任何其他方法的 JS 代码。

4

1 回答 1

25

有多个问题:

  1. ( Content-Security-PolicyCSP) 标头不能以这种方式工作。CSP 仅具有单个主机+端口组合(来源)的粒度。如果您不能允许所有脚本都拥有unsafe-eval,则任何脚本都不能拥有它。唯一可能的解决方法是不使用需要的脚本unsafe-eval(幸运的是,MathJax 不再需要,unsafe-eval因为MathJax 错误 256已修复)。

  2. allow语法是旧的 Mozilla 变体,不应使用。当前的语法是说default-src后跟允许作为所有内容的来源的方案或主机名或来源,然后script-src根据需要覆盖每个子类型的默认值(例如 )。除了 .之外,某些来源可能还支持其他来源关键字self。例如,script-src支持unsafe-eval意味着任何允许执行的脚本都可以运行 eval() 或 Function(),unsafe-inline这意味着任何可以支持某种内联脚本的标记都可以执行。允许unsafe-eval可能是可以接受的,但unsafe-inline几乎不能使用 script-src(否则,您根本不应该为 CSP 烦恼)。

  3. 正确的语法script-src如下:

     script-src 'self' cdnjs.cloudflare.com
    

    结合从https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js加载 MathJax

  4. MathJax 还使用内联样式属性,因此需要以下内容(除非已经允许),否则 MathJax 将Exception在尝试渲染数学时引发:

     style-src 'self' 'unsafe-inline'
    

    不能使用 CSP 让 JS 插入样式属性,并且没有 HTML 源中已经插入的样式属性生效。

  5. 在违反 CSP 的情况下,Firefox 13.0(至少)似乎不会立即“打电话回家”。大多数违规报告都会在事件发生后的某个时间提交。Chrome 在报告提交方面似乎更加积极,这将使其更容易测试。根据我的经验,Firefox 并不总是发送 CSP 报告——它可能使用某种启发式方法来不发送重复的消息。

最后,要使 MathJax 与 Content-Security-Protection 一起使用,您需要以下标头(假设您通过 CDNJS 使用 MathJax):

Content-Security-Policy: default-src 'self'; script-src 'self' cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline';

较旧的浏览器(例如 Firefox 13)过去需要额外的参数,例如options或需要使用非标准的标头名称,例如X-Content-Security-PolicyX-WebKit-CSP。由于用户代理现在支持标准标头,因此不再需要这些 hack。(除了 MSIE 与 MS Edge 相反。

2021 年更新:

CSP 版本 2 也允许在源中指定路径。但是,请注意,使用路径是一项重大更改,其中向后兼容性有点未知。有问题的部分是服务器需要在知道用户代理是否支持 CSP1 或 CSP2 之前发出 CSP 标头。

于 2012-06-08T12:45:47.297 回答