近来发现在知乎、 Github 上我最常用的 bookmarklet (书签小工具,就是那种一句话 Javascript 书签)——饭否分享失效了。打开 Console 一看,有这样的提示:“Content Security Policy: 页面设置阻止读取一项资源:已经阻止执行内联脚本。”大概是孤陋寡闻,之前还没听说过 Content Security Policy 这玩意儿,猜测又是和 Cross-Origin Resource Sharing 有关系的什么东西,就做了一番搜索。
CSP 是一个可以限制页面中哪些 src (包括脚本、图片等等)可以被允许的实验性 HTTP Header 。这是 W3C Candidate Recommendation ,而这个是 MDN 上的相关资料。简而言之又是一个 defend by depth 的产物,可以给 XSS 防范再加上一层保险:直接禁止掉 inline script 和 inline eval ,然后给出一个允许加载的资源域的白名单,这样即使有 XSS 过滤漏洞,也无法注入站外的脚本。
但是问题就来了:用户直接在地址栏里输入的 Javascript 应该被允许么? Bookmarklet 应该被允许么? W3 文档这么说:
Enforcing a CSP policy should not interfere with the operation of user-supplied scripts such as third-party user-agent add-ons and JavaScript bookmarklets.
可事实是 Firefox ( Chrome 估计也是)没有正确实现,把 bookmarklet 也给拦截了,同时拦截掉了的还有 Lastpass 这样的插件的 JS 脚本,这也顺便解释了为什么 Lastpass 在知乎首页上无法自动填充的问题。
Github 博客上介绍这个新措施的文章里也提到了这个问题,并且给出了一个“解决方案”——直接把浏览器的 CSP 支持给禁用就好了……