在我的Web应用程序中,我允许发布用户生成的内容以供公共使用,类似于Stackoverflow.
处理此问题的最佳做法是什么?
我目前处理用户生成内容的步骤是:
我使用MarkItUp让用户可以轻松地格式化他们的html.
在用户提交了更改后,我通过使用白名单方法的HTML Sanitizer (滚动到bottem)运行它.
如果清理过程已删除任何用户创建的内容,则不保存内容.然后我返回那里修改过的内容,并带有警告信息,"检测到并删除了一些非法内容标签,请仔细检查您的工作,然后再试一次."
如果内容干净地通过清理过程,我将原始html内容保存到数据库.
渲染到客户端时,我只是将原始html从db传递到页面.
这是一个完全合理的做法。对于典型的应用来说,这完全足够了。
将原始 HTML 列入白名单最棘手的部分是style属性和embed/ object。有人可能希望将 CSS 样式放入不受信任的格式化文本块(或者嵌入的 YouTube 视频)中,这是有正当理由的。此问题最常出现在 Feed 中。您不能信任提要条目中包含的任意文本块,但您也不想删除语法突出显示 CSS 或 Flash 视频等内容,因为这会从根本上改变内容并可能使任何阅读它的人感到困惑。style因为 CSS 可能包含危险的东西,例如 IE 中的行为,所以如果您决定允许该属性保留,您可能必须解析 CSS 。并且使用embed/object您可能需要将主机名列入白名单。
附加物:
在最坏的情况下,HTML 转义可见的所有内容可能会导致非常糟糕的用户体验。最好使用 HTML5 解析器之一来通过白名单来遍历 DOM。就如何向用户呈现经过净化的输出而言,这要灵活得多。您甚至可以执行以下操作:
<div class="sanitized">
<div class="notice">
This was sanitized for security reasons.
</div>
<div class="raw"><pre>
<script>alert("XSS!");</script>
</pre></div>
</div>
Run Code Online (Sandbox Code Playgroud)
然后.raw用 CSS 隐藏这些内容,并使用 jQuery 将单击处理程序绑定到在 和.sanitized div之间切换的:.raw.notice
CSS:
.raw {
display: none;
}
Run Code Online (Sandbox Code Playgroud)
jQuery:
$('.sanitized').click(function() {
$(this).find('.notice').toggle();
$(this).find('.sanitized').toggle();
});
Run Code Online (Sandbox Code Playgroud)