允许用户向您的网站添加自己的JavaScript代码会存在安全问题吗?

6

我计划创建一个开源教育网络应用程序,让人们可以添加和编辑内容(类似维基百科)。

但是,我希望添加另一个功能,允许用户使用JavaScript添加自己的交互式内容(就像JSFiddle一样)。

这样做存在哪些安全问题? 可选问题:这些问题如何解决?


你是指“自己的交互式” - 每个用户只能执行自己安装的脚本,还是“交互内容”,任何用户都可以上传代码,供其他人执行? - Bergi
用户可以上传代码,由他人执行。 - Yahya Uddin
这是很危险的。如果可以的话,应该避免它(例如只允许配置给定模块);如果你需要/想要它,你应该使用一些同行评审过程,以便拒绝恶意代码。 - Bergi
2个回答

9

您可以使用 HTML5沙盒 仅在IFrame中加载用户脚本。

您应该仅从与主站点不同的域托管用户内容。这将防止任何 XSS 攻击,如果攻击者说服用户直接访问页面(超出沙箱)。例如,如果您的网站是 www.example.com,则可以使用以下代码显示沙箱IFrame(请注意.org而不是.com,这是完全不同的域):

<iframe src="https://www.example.org/show_user_script.aspx?id=123" sandbox="allow-scripts"></iframe>

这将允许脚本,但会防止IFrame外的表单和导航。请注意,此方法仍可能存在用户hosting a phishing form to capture credentials的风险。您应确保在用户界面中清楚地界定站点与用户内容之间的边界。尽管我们没有指定allow-forms,但这仅会阻止直接提交表单,而不会阻止表单元素和JavaScript事件处理程序向外部域发送任何数据。 OWASP HTML5安全备忘单建议指出这是沙箱的目的:

对于不受信任的内容,请使用iframe的sandbox属性

在呈现IFrame之前,您应首先测试是否支持沙箱。
<iframe src="/blank.htm" sandbox="allow-scripts" id="foo"></iframe>

var sandboxSupported = "sandbox" in document.createElement("iframe");

if (sandboxSupported) {
    document.getElementById('foo').setAttribute('src', 'https://www.example.org/show_user_script.aspx?id=123');
}
else
{
    // Not safe to display IFrame
}

这种方法通过动态更改src而不是在sandboxSupportedfalse时重定向,可以更安全地进行操作,因为如果重定向没有及时发生,则不会意外呈现iframe。
作为一种更简单的替代方法,无需检查是否支持沙箱,您可以使用srcdocIFrame属性生成沙箱内容,确保所有内容都是HTML编码的:
例如: <html><head></head><body>This could be unsafe</body></html> 将呈现为 <iframe srcdoc="&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;This could be unsafe&lt;/body&gt;&lt;/html&gt;" sandbox="allow-scripts"></iframe> 或者您可以构建一个数据Blob对象,再次小心地进行HTML编码:
<body data-userdoc="&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;This could be unsafe&lt;/body&gt;&lt;/html&gt;">

<script>
var unsafeDoc = new Blob([document.body.dataset.userdoc], {type: 'text/html'});

var iframe = document.createElement('iframe');
iframe.src = window.URL.createObjectURL(unsafeDoc);
iframe.sandbox = 'allow-scripts';
</script>


当然,您也可以从JSON数据源设置unsafeDoc变量。不建议加载HTML文件,因为这具有与外部域相同的问题,攻击者可能会诱使用户直接加载该文件。此外,请不要尝试直接将用户内容写入脚本块。如上所示,data attributes是安全的方法,只要在服务器端输出用户数据时进行正确的HTML编码即可。在这些情况下,您可以将src保留为blank.html,因为不支持srcdoc的旧浏览器将简单地加载该URL。

正如@Snowburnt所提到的那样,没有什么可以阻止用户脚本将用户重定向到发生驱动下载的网站,但是这种方法假设用户已经更新了补丁,并且没有零日漏洞,这是一种安全的方法,因为它通过同源策略保护其最终用户及其在您网站上的数据。


同源策略不是保护用户免受驱动下载的吗? - whereswalden
@whereswalden:不,驱动程序下载实际上是浏览器漏洞利用 - 而不是实际下载。同源策略无法防止浏览器中的漏洞。 - SilverlightFox
这仍然是一个可行的选择吗?我想开发一个平台,让用户可以使用HTML、JS和CSS构建自己的“模块”。 - JCAguilera
1
@JCAguilera 是的,浏览器支持很好。正如所提到的,我建议使用带有srcdoc选项或Blob方法的sandbox,因为这些方法不需要购买另一个域名。 - SilverlightFox

1
一个大问题是跨站脚本攻击,用户添加代码告诉浏览器打开并运行其他站点的代码。比如他们添加了创建iFrame或指向网站并开始下载恶意代码的隐藏iFrame的内容。
没有简单的方法(感谢评论中的Bergi)来确保不创建任何元素和不进行任何ajax调用。
我曾经是提供此功能的网站的成员,但对于这些网站,我为自己的空间付费,因此我添加的任何漏洞都会给我的客户带来不便,在这种情况下,让它失误有点可以接受,因为这不是每个人的安全泄漏。
解决此问题的一种方法是为用户创建可定制的控件以添加互动性。优点是您可以控制添加的javascript,缺点是您的用户群体将不得不请求并等待您创建它们。

1
"intense parsing of the javascript"? 那几乎不可能奏效。你知道吗,每个javascript都可以写成没有字母数字字符的形式。代码过滤器注定会失败。 - Bergi
但是在那种情况下,JS Fiddle 如何处理这个问题,因为他们允许人们提交 JS。类似 HTML5 中 iframe 的沙盒功能是否可行? - Yahya Uddin
@jsfiddle确实允许脚本运行,但您从未打开过恶意链接,对吧?据我所知,嵌入的结果来自子域,因此由于同源策略,脚本无法对已登录用户进行恶意操作。 - Bergi
@jsfiddle旨在成为一个沙盒,通常使用它是作为用户基础之间的事实信任。就个人而言,除非是像我描述的那种情况,即特定用户负责其命名空间并且他们只会通过感染自己的网站来损害自己的客户,否则我不会发布允许自由使用JavaScript的生产系统。 - Snowburnt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接