Совместите предварительный HTML-код редактора ОМУ с проверкой HTML на стороне сервера (например, без встроенного кода JavaScript) - PullRequest
5 голосов
/ 15 мая 2010

Существует много вопросов о переполнении стека (например, Белый список, предотвращение XSS с контролем ОМУ в C # и Уценка ОМУ и на стороне сервера ) о том, как выполнить очистку Markdown на стороне сервера, созданную редактором WMD, чтобы убедиться, что созданный HTML-файл не содержит вредоносного сценария, например:

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

Но я не нашел хорошего способа закрыть отверстие на стороне клиента. Конечно, проверка клиента не является заменой очистки проверки на сервере, так как любой может притвориться клиентом и ПОСЛАТЬ вам грязную Markdown. И если вы чистите HTML-код на сервере, злоумышленник не может сохранить плохой HTML-код, поэтому никто другой не сможет увидеть его позже и украсть свои файлы cookie или перехватить сеанс с помощью плохого сценария. Таким образом, есть веские аргументы в пользу того, что не стоит применять правила без сценариев на панели предварительного просмотра ОМУ.

Но представьте, что злоумышленник нашел способ проникновения злонамеренной Markdown на сервер (например, скомпрометированный фид с другого сайта или контент, добавленный до исправления ошибки XSS). Ваш белый список на стороне сервера, применяемый при переводе уценки в HTML, обычно предотвращает показ этой плохой уценки пользователям. Но если злоумышленник может заставить кого-то отредактировать страницу (например, опубликовав другую запись, в которой говорится, что вредоносная запись содержит неработающую ссылку, и попросить кого-то исправить ее), то любой, кто редактирует страницу, получает свои файлы cookie. Это по общему признанию угловой случай, но это все еще может стоить защищаться.

Кроме того, возможно, плохая идея разрешать в окне предварительного просмотра клиента использовать другой HTML, чем позволяет ваш сервер.

Команда Stack Overflow закрыла эту дыру, внеся изменения в ОМУ. Как они это сделали?

[ПРИМЕЧАНИЕ: я уже понял это, но для этого потребовалась некоторая хитрая отладка JavaScript, поэтому я отвечаю на свой вопрос здесь, чтобы помочь другим, которые могут захотеть сделать то же самое] .

Ответы [ 2 ]

6 голосов
/ 15 мая 2010

Одно из возможных исправлений в wmd.js, в методе pushPreviewHtml(). Вот оригинальный код из версии WMD с переполнением стека на GitHub :

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

Вы можете заменить его некоторым кодом очистки. Вот адаптация кода, который переполнение стека использует в ответ на этот пост , который ограничивается белым списком тегов, а для элементов IMG и A ограничивается белым списком атрибутов (и в определенном порядке тоже !). См. Сообщение Meta Stack Overflow Какие теги HTML разрешены для переполнения стека, сбоя сервера и суперпользователя? для получения дополнительной информации о белом списке.

Примечание: этот код, безусловно, можно улучшить, например, разрешить атрибуты из белого списка в любом порядке. Он также запрещает использование mailto: URL-адресов, что, вероятно, полезно на интернет-сайтах, но на вашем собственном интранет-сайте это может быть не лучшим подходом.

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 
}

Также обратите внимание, что это исправление отсутствует в версии Переполнение стека WMD на GitHub - очевидно, что изменение было внесено позже и не возвращено в 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 голосов
/ 15 мая 2010

Это не проблема безопасности, позволяющая локальному пользователю выполнять сценарии в контексте страницы, если это невозможно для третьей стороны предоставить сценарий. Без этого редактор всегда может ввести URL-адрес javascript:, находясь на вашей странице, или использовать Firebug или что-то подобное.

...