我正在尝试使用MathJax作为我们的网络应用程序的一部分,该应用程序使用非常严格的Content Security Policy (CSP)。问题在于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()
下方的同一原点内的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 Console(位于Tools - Web Developer中):
[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
但是,我没有收到“报告 - uri”的CSP报告。 (如您所见,我目前正在通过自定义localhost端口运行测试而不使用SSL,以防有所不同。static
之前的冒号不是拼写错误,我保留所有以冒号开头的路径部分对于应用程序的内部使用,所有用户内容都可以自由定义其他URL。)
我对unsafe-eval
属性的使用是否不正确或是否仅允许对'self'的子集进行unsafe-eval?目的是仅允许对同一来源的unsafe-eval路径前缀/:static/math
,“self
”的严格CSP JS代码执行,以及任何其他方法的JS代码。
答案 0 :(得分:17)
存在多个问题:
Content-Security-Policy
(CSP)标头无法正常工作。 CSP仅具有单个主机+端口组合(原点)的粒度。如果您不允许所有脚本都拥有unsafe-eval
,则没有脚本可以拥有它。唯一可行的解决方法是不使用需要unsafe-eval
的脚本(幸运的是,自MathJax bug 256修复后,MathJax不再需要unsafe-eval
。)
allow
语法是旧的Mozilla变体,不应使用。当前语法是说default-src
后跟允许作为所有内容源的方案或主机名或来源,然后根据需要覆盖每个子类型的默认值(例如script-src
)。除self
之外,某些来源可能还支持其他来源关键字。例如,script-src
支持unsafe-eval
,这意味着任何允许执行的脚本都允许运行eval()或Function(),而unsafe-inline
意味着任何一个标记允许支持某种内联脚本执行。允许unsafe-eval
可能是可以接受的,但是unsafe-inline
与script-src几乎没有关系(否则,你根本不应该打扰CSP)。
script-src
的正确语法如下:
script-src 'self' cdnjs.cloudflare.com
结合从https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js
MathJax还使用内联样式属性,因此需要关注(除非已经允许)或MathJax将在尝试渲染数学时引发Exception
:
style-src 'self' 'unsafe-inline'
不可能使用CSP来允许JS插入样式属性,并且不会在HTML源代码中插入样式属性以产生效果。
在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
,或者需要使用非标准的headere名称,例如X-Content-Security-Policy
或X-WebKit-CSP
。由于用户代理现在支持标准标题,因此不再需要这些黑客攻击。 ( MSIE除外,与MS Edge相反。)