Разумно ли использовать jQuery для добавления тегов в белый список? Существуют ли существующие решения на JavaScript?

Моя проблема

Я хочу очистить HTML, вставленный в текстовый редактор (сейчас FCK 1.6). Очистка должна проводиться на основе белого списка тегов (и, возможно, другого списка с атрибутами). Это в первую очередь не для предотвращения XSS, а для удаления уродливого HTML.

В настоящее время я не вижу возможности сделать это на сервере, поэтому полагаю, что это нужно делать на JavaScript.

Текущие идеи

Я нашел плагин jquery-clean, но, насколько я понимаю, он использует регулярные выражения для выполнения своей работы, и мы знаю, что это небезопасно.

Поскольку я не нашел другого решения на основе JS, я сам начал его использовать, используя jQuery. Он будет работать, создав jQuery-версию вставленного HTML ($(pastedHtml)), а затем пройдя по результирующему дереву, удалив каждый элемент, не соответствующий белому списку, просмотрев атрибут tagName.

Мои вопросы

  • Это лучше?
  • Могу ли я доверять jQuery, чтобы он хорошо представлял вставленный контент (могут быть несовпадающие конечные теги и что-то еще)?
  • Есть ли лучшее решение, которое я не мог найти?

Обновлять

Это мое текущее решение на основе jQuery (подробное и не тщательно проверяемое):

function clean(element, whitelist, replacerTagName) {
    // Use div if no replace tag was specified
    replacerTagName = replacerTagName || "div";

    // Accept anything that jQuery accepts
    var jq = $(element);    

    // Create a a copy of the current element, but without its children
    var clone = jq.clone();
    clone.children().remove();

    // Wrap the copy in a dummy parent to be able to search with jQuery selectors
    // 1)
    var wrapper = $('<div/>').append(clone);

    // Check if the element is not on the whitelist by searching with the 'not' selector
    var invalidElement = wrapper.find(':not(' + whitelist + ')');

    // If the element wasn't on the whitelist, replace it.
    if (invalidElement.length > 0) {
       var el = $('<' + replacerTagName + '/>'); 
       el.text(invalidElement.text()); 
       invalidElement.replaceWith(el);   
    }

    // Extract the (maybe replaced) element
    var cleanElement = $(wrapper.children().first());

    // Recursively clean the children of the original element and
    // append them to the cleaned element
    var children = jq.children();
    if (children.length > 0) {
        children.each(function(_index, thechild) {
                          var cleaned = clean(thechild, whitelist, replacerTagName);
                          cleanElement.append(cleaned);
                      });
      } 
    return cleanElement;
}

Меня интересуют некоторые моменты (см. Комментарии в коде);

  1. Мне действительно нужно обернуть мой элемент фиктивным родительским элементом, чтобы иметь возможность сопоставить его с jQuery ": not"?
  2. Это рекомендуемый способ создания нового узла?

person Peter Jaric    schedule 17.03.2011    source источник
comment
Я не могу в комментарии предложить, как это можно сделать на стороне сервера, но JS доступен для конечного пользователя, и мы не доверяем конечным пользователям. Это может выполняться на стороне клиента, но это также необходимо проверить на стороне сервера.   -  person David says reinstate Monica    schedule 17.03.2011
comment
@David Thomas: Вот почему я писал не в первую очередь для предотвращения XSS, но я вижу, как это применимо и к моему варианту использования. Однако моя среда - это существующая CMS, и сделать это на стороне сервера будет намного сложнее. Также стоит отметить, что пользователи редактора - это вошедшие в систему сотрудники, у которых есть доступ к изменению содержимого страницы и даже структуры сайта.   -  person Peter Jaric    schedule 17.03.2011
comment
Я имею в виду, что они могут создать хаос, если захотят. Я просто хочу, чтобы было сложнее делать ошибки и легче поступать правильно.   -  person Peter Jaric    schedule 17.03.2011
comment
аааа ... ну, в этом случае клиентская сторона, вероятно, в порядке :)   -  person David says reinstate Monica    schedule 17.03.2011


Ответы (1)


Если вы используете возможности браузера по исправлению HTML (например, вы копируете форматированный текст в innerHTML пустого div и берете результирующее дерево DOM), HTML будет гарантированно действителен (способ его исправления зависит от браузера. ). Хотя, наверное, это и так делает богатый редактор.

Собственное преобразование DOM текста в верхнюю часть jQuery, вероятно, также безопасно, но определенно медленнее, поэтому я бы его избегал.

Использование белого списка на основе механизма выбора jQuery может быть несколько сложным, потому что удаление элемента при сохранении его дочерних элементов может сделать документ недействительным, поэтому браузер исправит его, изменив дерево DOM, что может сбить с толку сценарий, пытающийся перебирать недопустимые элементы. . (Например, вы разрешаете ul и li, но не ol; сценарий удаляет корневой элемент списка, голые элементы li недействительны, поэтому браузер снова оборачивает их в ul, этот ul будет пропущен скриптом очистки.) Если вы выбросите ненужные элементы. вместе со всеми их детьми я не вижу в этом никаких проблем.

person Tgr    schedule 17.03.2011
comment
Благодарность! Вы поднимаете вопрос, о котором я даже не думал. Я обновил свой вопрос исходным кодом моего текущего решения, в котором я не учел то, что вы говорите. Когда я запускаю свою функцию, она возвращает HTML, который недействителен (я пробовал ваш пример, разрешив li, но заменив ul, например, на div), и я могу добавить его в DOM. Это с Chromium в Ubuntu. Придется посмотреть, как это работает и в других браузерах. - person Peter Jaric; 21.03.2011
comment
о производительности jQuery ... если jQuery не очень медленный (а я так не думаю), я сомневаюсь, что пользователь заметит, когда он вставляет HTML в текстовую область редактора. - person Peter Jaric; 21.03.2011