Alinhe a visualização do editor WMD HTML com validação HTML do lado do servidor (por exemplo, sem código JavaScript incorporado)

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

Pergunta

Existem muitas questões de transbordamento de pilha (por exemplo Lista de permissões, impedindo o XSS com controle de armas de destruição em massa em C# e WMD Markdown e servidor) Sobre como fazer a lavagem do servidor de Markdown produzida pelo Editor WMD para garantir que o HTML gerado não contenha script malicioso, assim:

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

Mas também não encontrei uma boa maneira de conectar o buraco no lado do cliente. A validação do cliente não é um substituto para limpar a validação no servidor, é claro, pois qualquer pessoa pode fingir ser um cliente e publicar seu markdown desagradável. E se você estiver esfregando o HTML no servidor, um invasor não poderá salvar o HTML ruim para que ninguém mais possa vê -lo mais tarde e ter seus cookies roubados ou sessões seqüestradas pelo script ruim. Portanto, há um caso válido a ser feito de que pode não valer a pena aplicar regras de NO-script no painel de visualização de WMD também.

Mas imagine que um invasor encontrou uma maneira de colocar a marcação maliciosa no servidor (por exemplo, um feed comprometido de outro site ou conteúdo adicionado antes que um bug XSS fosse corrigido). Sua lista de permissões do lado do servidor se aplicava ao traduzir o Markdown para HTML normalmente impedia que esse mau markdown fosse mostrado aos usuários. Mas se o atacante pudesse fazer com que alguém edite a página (por exemplo, publicando outra entrada dizendo que a entrada maliciosa tinha um link quebrado e pedindo a alguém para consertar), qualquer pessoa que edite a página receba seus cookies sequestrados. É reconhecidamente um caso de canto, mas ainda pode valer a pena defender.

Além disso, é provavelmente uma má idéia permitir que a janela de visualização do cliente permitirá diferentes HTML que o seu servidor permitirá.

A equipe do Stack Overflow conectou esse buraco fazendo alterações no WMD. Como eles fizeram isso?

Nota: eu já descobri isso, mas exigiu uma depuração complicada de JavaScript, então estou respondendo minha própria pergunta aqui para ajudar outras pessoas que querem fazer essa a mesma coisa.

Foi útil?

Solução

Uma correção possível está em wmd.js, no pushPreviewHtml() método. Aqui está o código original do Versão de pilha de transbordamento da WMD no github:

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

Você pode substituí -lo por algum código de limpeza. Aqui está uma adaptação do código que o Stack Overflow usa em resposta a este post, que se restringe a uma lista de permissões de tags, e para o IMG e um elementos, restringe -se a uma lista de permissões de atributos (e em uma ordem específica também!). Veja o post de meta pilha Quais tags HTML são permitidas no excesso de pilha, falha do servidor e super usuário? Para mais informações sobre a lista de permissões.

NOTA: Este código certamente pode ser aprimorado, por exemplo, para permitir atributos de permissões em qualquer ordem. Ele também não permite o Mailto: URLs, o que provavelmente é uma coisa boa nos sites da Internet, mas no seu próprio site da Intranet, pode não ser a melhor abordagem.

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 
}

Observe também que essa correção não está no Versão de pilha de transbordamento da WMD no github- Claramente, a mudança foi feita mais tarde e não foi verificada no Github.

ATUALIZAÇÃO: Para evitar quebrar o recurso em que os hiperlinks são criados automaticamente quando você digita um URL, você também precisará fazer alterações no Showdown.js, como abaixo:

Código original:

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;
}

Código fixo:

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;
}

Outras dicas

Não é um problema de segurança permitir que o usuário local execute scripts no contexto da página, desde que seja impossível para terceiros fornecer o script. Sem o editor fazendo isso, o usuário sempre pode entrar em um javascript: URL enquanto estiver na sua página ou use Firebug ou algo semelhante.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top