Теперь, когда все основные браузеры поддерживают изолированные фреймы iframe, есть гораздо более простой способ, который, на мой взгляд, может быть безопасным. Я был бы рад, если бы этот ответ могли просмотреть люди, более знакомые с такого рода проблемами безопасности.
ПРИМЕЧАНИЕ. Этот метод определенно не будет работать в 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);
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), чтобы убедиться, что он вышел из строя перед выполнением любых скриптов. Мне было бы интересно узнать, есть ли какие-либо браузеры, у которых есть проблемы с этим, или какие-либо крайние случаи, которые я упускаю.