Теперь, когда все основные браузеры поддерживают встроенные песочницы, есть гораздо более простой способ, которым я считаю безопасным. Я был бы рад, если бы этот ответ был рассмотрен людьми, которые более знакомы с такой проблемой безопасности.
ПРИМЕЧАНИЕ. Этот метод определенно не будет работать в IE 9 и более ранних версиях. См. эту таблицу для версий браузера, которые поддерживают «песочницу». (Примечание: таблица, кажется, говорит, что она не будет работать в Opera Mini, но я только попробовал, и она работала.)
Идея состоит в том, чтобы создать скрытый iframe с отключенным JavaScript, вставить в него ненадежный HTML-код и дать ему возможность его проанализировать. Затем вы можете пройтись по дереву DOM и скопировать теги и атрибуты, которые считаются безопасными.
Указанные здесь белые списки являются лишь примерами. Что лучше всего сделать в белом списке, будет зависеть от приложения. Если вам нужна более сложная политика, чем просто белые списки тегов и атрибутов, то этот метод может быть учтен, но не кодом этого примера.
var tagWhitelist_ = {
'A': true,
'B': true,
'BODY': true,
'BR': true,
'DIV': true,
'EM': true,
'HR': true,
'I': true,
'IMG': true,
'P': true,
'SPAN': true,
'STRONG': true
};
var attributeWhitelist_ = {
'href': true,
'src': true
};
function sanitizeHtml(input) {
var iframe = document.createElement('iframe');
if (iframe['sandbox'] === undefined) {
alert('Your browser does not support sandboxed iframes. Please upgrade to a modern browser.');
return '';
}
iframe['sandbox'] = 'allow-same-origin';
iframe.style.display = 'none';
document.body.appendChild(iframe); // necessary so the iframe contains a document
iframe.contentDocument.body.innerHTML = input;
function makeSanitizedCopy(node) {
if (node.nodeType == Node.TEXT_NODE) {
var newNode = node.cloneNode(true);
} else if (node.nodeType == Node.ELEMENT_NODE && tagWhitelist_[node.tagName]) {
newNode = iframe.contentDocument.createElement(node.tagName);
for (var i = 0; i < node.attributes.length; i++) {
var attr = node.attributes[i];
if (attributeWhitelist_[attr.name]) {
newNode.setAttribute(attr.name, attr.value);
}
}
for (i = 0; i < node.childNodes.length; i++) {
var subCopy = makeSanitizedCopy(node.childNodes[i]);
newNode.appendChild(subCopy, false);
}
} else {
newNode = document.createDocumentFragment();
}
return newNode;
};
var resultElement = makeSanitizedCopy(iframe.contentDocument.body);
document.body.removeChild(iframe);
return resultElement.innerHTML;
};
Вы можете попробовать это здесь .
Обратите внимание, что в этом примере я запрещаю атрибуты и теги стилей. Если вы позволите им, вы, вероятно, захотите проанализировать CSS и убедиться, что он безопасен для ваших целей.
Я проверил это на нескольких современных браузерах (Chrome 40, Firefox 36 Beta, IE 11, Chrome для Android) и на одном старом (IE 8), чтобы убедиться, что он был запущен перед выполнением любых сценариев. Мне было бы интересно узнать, есть ли какие-либо браузеры, которые имеют проблемы с ним, или какие-либо крайние случаи, которые я пропускаю.