对齐与服务器端HTML验证的大规模杀伤性武器编辑器的预览HTML(例如,没有嵌入的JavaScript代码)

StackOverflow https://stackoverflow.com/questions/2837593

有许多堆栈溢出的问题(比如 白名单,防止XSS与WMD控制在C# WMD减价及有关如何执行服务器侧擦洗降价的服务器端 的)所生产的WMD编辑,以确保生成的HTML不包含恶意脚本,如下所示:

<img onload="alert('haha');" 
   src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" />

但我没有找到一个很好的办法来插在客户端的孔太。客户端验证是不是当然的服务器上擦洗验证的替代品,因为任何人都可以伪装成客户端和POST你讨厌的降价。如果你正在清理服务器上的HTML,攻击者无法保存HTML不好所以没有人会是以后能看到它,并有自己的cookies窃取或会话由不良脚本劫持。因此,有被提出,它可能不值得强制执行无脚本规则在大规模杀伤性武器预览窗格太有效的情况下。

但是想象攻击者找到一种方式来获得恶意降价到服务器(例如,从另一站点或XSS错误之前添加的内容泄露进料是固定的)。服务器端转换降价时HTML通常会阻止坏的降价被显示给用户白名单应用。但是,如果攻击者可以找人来编辑的页面(例如,通过张贴另一个项目称恶意项有断开的链接,并要求有人来修理的话),那么任何人谁编辑的页面得到他们的cookie劫持。这是无可否认的角的情况下,但它仍然可能是值得抵御。

此外,它可能是一个坏主意,让客户预览窗口,让不同的HTML比你的服务器将允许。

在堆栈溢出团队已经通过更改WMD塞住该孔。他们是如何做到的呢?

[注:我已经想通了这一点,但它需要一些棘手的JavaScript调试,所以我在这里回答我的问题,帮助他人谁可能要执行的部份同样的事情。

有帮助吗?

解决方案

一种可能的解决方法是在wmd.js,在pushPreviewHtml()方法。下面是来自堆栈溢出WMD的版本的原始代码在GitHub

if (wmd.panels.preview) {
    wmd.panels.preview.innerHTML = text; 
}

您可以使用一些清理代码替换它。下面的代码的适配该堆栈溢出使用响应于该交,它限制了标签的白名单,以及用于IMG和A元素,限制对属性的白名单(在一个特定的顺序呢!)。见元堆栈溢出后的 什么HTML标签堆栈溢出,服务器故障,以及超级用户允许? 的白名单上的更多信息。

注意:这个代码能够可靠地改善,例如允许以任何顺序列入白名单属性。它还禁止的mailto:网址,这可能是在互联网上的网站,但在自己的Intranet站点的好事也未必是最好的方法。

if (wmd.panels.preview) {

    // Original WMD code allowed JavaScript injection, like this:
    //    <img src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" onload="alert('haha');"/>
    // Now, we first ensure elements (and attributes of IMG and A elements) are in a whitelist,
    // and if not in whitelist, replace with blanks in preview to prevent XSS attacks 
    // when editing malicious Markdown.
    var okTags = /^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|pre|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i;
    var okLinks = /^(<a\shref="(\#\d+|(https?|ftp):\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\stitle="[^"<>]+")?\s?>|<\/a>)$/i;
    var okImg = /^(<img\ssrc="https?:(\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\swidth="\d{1,3}")?(\sheight="\d{1,3}")?(\salt="[^"<>]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i;
    text = text.replace(/<[^<>]*>?/gi, function (tag) {
        return (tag.match(okTags) || tag.match(okLinks) || tag.match(okImg)) ? tag : ""
    })

    wmd.panels.preview.innerHTML = text;  // Original code 
}

另外请注意,此修复程序是不是在堆栈溢出大规模杀伤性武器的GitHub上版本 - 明确变更后来并没有作出检入GitHub上。

更新:为了避免破坏其中超链接是自动创建的,当你在网址输入功能,您还需要进行修改,showdown.js,象下面这样:

<强>原始代码:

var _DoAutoLinks = function(text) {

    text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>");

    // Email addresses: <address@domain.foo>

    /*
        text = text.replace(/
            <
            (?:mailto:)?
            (
                [-.\w]+
                \@
                [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
            )
            >
        /gi, _DoAutoLinks_callback());
    */
    text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
        function(wholeMatch,m1) {
            return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
        }
    );

    return text;
}

<强>固定代码:

var _DoAutoLinks = function(text) {
    // use simplified format for links, to enable whitelisting link attributes
    text = text.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi, "$1<$2$3>$4");
    text = text.replace(/<((https?|ftp):[^'">\s]+)>/gi, '<a href="$1">$1</a>');
    return text;
}

其他提示

这不是一个安全问题,允许本地用户在页面内容,只要它是不可能的任何第三方提供的脚本执行脚本。 如果没有编辑器做它,用户可以随时进入一个javascript:网址,而您的网页或使用Firebug的或类似的东西。

这是
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top