我计划创建一个开源教育网络应用程序,人们可以在其中添加和编辑内容(有点像维基百科)。
但是,我希望添加另一个功能,允许用户使用 JavaScript 添加他们自己的交互式内容。(类似于 JSFiddle 的做法)
这样做的安全问题是什么?可选问题:如何克服这些问题?
我计划创建一个开源教育网络应用程序,人们可以在其中添加和编辑内容(有点像维基百科)。
但是,我希望添加另一个功能,允许用户使用 JavaScript 添加他们自己的交互式内容。(类似于 JSFiddle 的做法)
这样做的安全问题是什么?可选问题:如何克服这些问题?
是的,您可以使用HTML5 Sandbox仅在 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 之外的表单和导航。请注意,这种方法仍然可能使用户托管网络钓鱼表单以获取凭据的风险。您应该确保在用户界面中您的站点和用户内容之间的界限是清晰的。即使我们没有指定allow-forms
,这只会阻止直接提交表单,它不会阻止表单元素和 JavaScript 事件处理程序向外部域发送任何数据。
OWASP 上的HTML5 安全备忘单指南指出这是沙箱的目的:
对不受信任的内容使用 iframe 的沙箱属性
在渲染 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
,而不是重定向的路程,如果sandboxSupported
是false
因为这样的iframe不小心就会被如果重定向不及时发生呈现。
作为更简单的替代方案,无需检查是否支持沙箱,您可以使用srcdoc
IFrame 属性生成沙箱内容,确保所有内容都是 HTML 编码的:
例如
<html><head></head><body>This could be unsafe</body></html>
将被渲染为
<iframe srcdoc="<html><head></head><body>This could be unsafe</body></html>" sandbox="allow-scripts"></iframe>
或者你可以构造一个数据 blob 对象,小心地再次进行 HTML 编码:
<body data-userdoc="<html><head></head><body>This could be unsafe</body></html>">
<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>
当然,您也可以unsafeDoc
从 JSON 数据源设置变量。不建议加载 HTML 文件,因为这与必须来自外部域的问题相同,因为攻击者可以诱使用户直接加载该文件。
另外,请不要试图将用户内容直接写入脚本块。如上所示,数据属性是执行此操作的安全方法,只要对用户数据执行正确的 HTML 编码,因为它是在服务器端输出的。
在这些情况下,您可以保留src
,blank.html
因为不支持的旧浏览器srcdoc
只会加载该 URL。
正如@Snowburnt 提到的,没有什么可以阻止用户脚本将用户重定向到发生偷渡式下载的站点,但是这种方法,假设用户是最新的补丁,并且没有零日漏洞,这是一种安全的方法,因为它通过同源策略保护其最终用户及其在您网站上的数据。
一个大问题是跨站点脚本,用户添加代码告诉浏览器打开和运行来自其他站点的代码。假设他们添加了一些创建 iFrame 或指向某个站点的隐藏 iFrame 并开始下载恶意代码的内容。
没有简单的方法来解决它(感谢评论中的 Bergi)来确保没有创建任何元素并且没有进行 ajax 调用。
我一直是提供此功能的网站的成员,但对于那些我为自己的空间付费的网站,因此我添加的任何漏洞都给我自己的客户带来了不便,在这种情况下,让它溜走会好一点,因为它不是每个人的安全漏洞。
解决此问题的一种方法是为用户创建可自定义的控件以用于添加交互性。优点是您可以控制正在添加的 javascript,缺点是您的用户群必须请求然后等待您创建它们。