Как проверить, безопасна ли строка HTML? - PullRequest
1 голос
/ 05 сентября 2011

В моем приложении мне нужно отправлять и получать HTML в виде строки. Я хотел бы сохранить безопасность, и поэтому мне нужно проверить, соответствуют ли элементы dom в строке допустимым тегам, а также допустимы ли объявления стилей и нет ли внедренных сценариев. Первое, что приходит на ум, это, конечно, регулярное выражение строки, но это утомительно, может быть с ошибками и наверняка неэффективно. Вторая идея - использовать что-то под названием XPath, но хотя я читал некоторые материалы на сайте MDN, я все еще не знаю, как реализовать этот пример кода:

const XPathResult           = Components.interfaces.nsIDOMXPathResult;

const ALLOWED_TAGS          = ['div', 'span', 'b', 'i', 'u', 'br', 'font', 'img'];
const ALLOWED_STYLES        = ['font-weight', 'font-size', 'font-family', 'text-decoration', 'color', 'background-color'];
const ALLOWED_ATTRIBUTES    = ['style', 'name'];

const XPATH_PART_TAGS = ALLOWED_TAGS.map(function (v) {
    return "name() != '" + v + "' and name() != '" + v.toUpperCase() + "'"; // case insensitive
}).join(' and ');

const XPATH_PART_ATTRS = ALLOWED_ATTRIBUTES.map(function (v) {
    return "name() != '" + v + "' and name() != '" + v.toUpperCase() + "'"; // case insensitive
}).join(' and ');


const XPATH_BAD_TAGS        = "//*[(namespace-uri() != 'http://www.w3.org/1999/xhtml') or (" + XPATH_PART_TAGS + ")]";
const XPATH_BAD_ATTRIBUTES  = "//@*[((namespace-uri() != 'http://www.w3.org/1999/xhtml') and (namespace-uri() != '')) or (" + XPATH_PART_ATTRS+ ")]";
const XPATH_STYLE           = "//@*[name() = 'style']";


/**
 * Checks if inline style definition is considered secure
 *
 * @param {String} styleValue value of style attribute
 * @return bool
 */
function isStyleSecure(styleValue) {
    var styles = styleValue.split(';'),
        style,
        name, value,
        i, l;
    for (i = 0, l = styles.length; i < l; i++) {
        style = styles[i].trim();
        if (style === '') {
            continue;
        }
        style = style.split(':', 2);
        if (style.length !== 2) {
            return false;
        }
        name = style[0].trim().toLowerCase();
        value = style[1].trim();

        if (ALLOWED_STYLES.indexOf(name) === -1) {
            return false;
        }
    }
    return true;
}

/**
 * Singleton that verifies if given XHTML document fragment is considered secure.
 * Uses whitelist-based checks on tag names, attribute names and document namespaces.
 *
 * @class
 * @namespace core.SecurityFilter.MessageSecurityFilter
 */
var MessageSecurityFilter = {
    /**
     * Checks if given document fragment is safe
     *
     * @param {nsIDOMElement} element root element of the XHTML document fragment to analyze
     * @return {bool} true if fragment is safe, false otherwise
     */
    isSecure: function SecurityFilter_isSecure(element) {
        var document = element.ownerDocument,
            result,
            attr;

        result = document.evaluate('//*', element, null, XPathResult.ANY_TYPE, null);

        result = document.evaluate(XPATH_BAD_TAGS, element, null, XPathResult.ANY_TYPE, null);
        if (result.iterateNext()) {
            return false;
        }
        result = document.evaluate(XPATH_BAD_ATTRIBUTES, element, null, XPathResult.ANY_TYPE, null);
        if ((attr = result.iterateNext())) {
            return false;
        }

        result = document.evaluate(XPATH_STYLE, element, null, XPathResult.ANY_TYPE, null);
        while ((attr = result.iterateNext())) {
            if (!isStyleSecure(attr.nodeValue)) {
                return false;
            }
        }

        return true;
    }

};

И первая идея состояла в том, чтобы создать documentFragment, а затем проверить его узлы либо с помощью treeWalker, либо просто следовать dom-дереву с помощью .firstChild и т. Д. Но я полагаю, что это решение небезопасно, поскольку оно оставит меня открытым для всех внедренных сценариев. Я прав?

Есть ли другой способ?

Ответы [ 2 ]

1 голос
/ 05 сентября 2011

Не катите свое собственное дезинфицирующее средство. Используйте тот, который был написан кем-то, кто знает темные уродливые углы HTML, CSS и JS.

См. http://code.google.com/p/google-caja/wiki/JsHtmlSanitizer для дезинфицирующего средства JavaScript.

0 голосов
/ 05 сентября 2011

Уровень безопасности, который вам нужен, зависит от того, как вы обрабатываете HTML.Если вы отправляете его по электронной почте или отображаете на веб-сервере, вам нужно быть намного более осторожным, чем если бы вы просто анализировали текст на нем.

Предполагая, что вы отображаете это на веб-сервереЭто очень сложная проблема, и вам следует использовать очиститель HTML, такой как http://htmlpurifier.org/ и , чтобы подписаться на обновления безопасности , возможно, даже найти способ автоматически получать обновления.Для дополнительной безопасности также используйте iframe.Также обратите особое внимание, если вы каким-то образом избегаете HTML.

Конечно, правильный ответ может быть совершенно другим в зависимости от фактического контекста вашей проблемы.Вышеприведенное должно обрабатывать наиболее распространенный случай.

Также см. Соответствие открытых тегов RegEx, за исключением автономных тегов XHTML

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...