代码之家  ›  专栏  ›  技术社区  ›  Justin Grant

将WMD编辑器的预览HTML与服务器端的HTML验证(例如,没有嵌入的javascript代码)对齐。

  •  5
  • Justin Grant  · 技术社区  · 15 年前

    有许多堆栈溢出问题(例如 Whitelisting, preventing XSS with WMD control in C# WMD Markdown and server-side )关于如何对WMD编辑器生成的标记进行服务器端清理,以确保生成的HTML不包含恶意脚本,如下所示:

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

    但我也没有找到一个很好的方法来堵住客户端的漏洞。当然,客户机验证并不能代替服务器上的清理验证,因为任何人都可以假装是客户机并发布你的恶意降价。如果你在服务器上清除HTML,攻击者就无法保存错误的HTML,因此以后没有人能够看到它,而且他们的cookie被盗或会话被错误的脚本劫持。因此,有一个有效的案例需要说明,在WMD预览窗格中也不需要强制执行任何脚本规则。

    但是,假设攻击者找到了一种方法来恶意攻击服务器(例如,来自另一个站点的泄露源,或修复XSS错误之前添加的内容)。将降价转换为HTML时应用的服务器端白名单通常会阻止向用户显示这种糟糕的降价。但是,如果攻击者可以让某人编辑页面(例如,通过发布另一个条目说恶意条目有一个断开的链接并要求某人修复),那么任何编辑页面的人都会被劫持cookie。诚然,这是一个不切实际的案件,但仍值得进行辩护。

    另外,允许客户机预览窗口允许与服务器允许的不同的HTML可能是一个坏主意。

    堆栈溢出团队已通过更改WMD来堵塞此孔。他们是怎么做到的?

    [注意:我已经解决了这个问题,但它需要一些复杂的javascript调试,所以我在这里回答自己的问题,以帮助其他可能想做同样事情的人] .

    2 回复  |  直到 10 年前
        1
  •  6
  •   Community CDub    8 年前

    一种可能的修复方法是在wmd.js中, pushPreviewHtml() 方法。这是原始代码 Stack Overflow version of WMD on GitHub :

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

    您可以用一些清理代码替换它。下面是堆栈溢出使用的代码的改编 in response to this post 它限制了标记的白名单,对于img和a元素,也限制了属性的白名单(也按特定的顺序!).参见元堆栈溢出日志 What HTML tags are allowed on Stack Overflow, Server Fault, and Super User? 有关白名单的更多信息。

    注意:这段代码当然可以改进,例如允许以任何顺序白名单属性。它也不允许mailto:urls,这在Internet站点上可能是一件好事,但在您自己的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上的WMD堆栈溢出版本 --很明显,更改是在稍后进行的,而不是签回Github。

    更新:为了避免破坏在输入URL时自动创建超链接的功能,还需要对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;
    }
    
        2
  •  2
  •   ThiefMaster    15 年前

    允许本地用户在页面上下文中执行脚本不是一个安全问题,只要任何第三方都不可能提供脚本。 如果编辑器不这样做,用户可以始终输入 javascript: 在你的网页上或使用Firebug或类似的东西时的URL。