Teraz, gdy wszystkie główne przeglądarki obsługują elementy iframe w piaskownicy, myślę , że istnieje znacznie prostszy sposób, który może być bezpieczny. Chciałbym, żeby ta odpowiedź została przejrzana przez osoby lepiej zaznajomione z tego rodzaju kwestiami bezpieczeństwa.
UWAGA: Ta metoda na pewno nie będzie działać w IE 9 i wcześniejszych. Zobacz tę tabelę dla wersji przeglądarek obsługujących piaskownicę. (Uwaga: w tabeli wydaje się, że nie działa w Operze Mini, ale właśnie spróbowałem i zadziałało).
Chodzi o to, aby utworzyć ukryty element iframe z wyłączoną obsługą JavaScript, wkleić do niego niezaufany kod HTML i pozwolić mu go przeanalizować. Następnie możesz przejść po drzewie DOM i skopiować tagi i atrybuty, które są uważane za bezpieczne.
Białe listy pokazane tutaj to tylko przykłady. To, co najlepiej umieścić na białej liście, zależy od aplikacji. Jeśli potrzebujesz bardziej wyrafinowanych zasad niż tylko białe listy tagów i atrybutów, można je uwzględnić tą metodą, ale nie w tym przykładowym kodzie.
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;
};
Możesz to wypróbować tutaj .
Zwróć uwagę, że w tym przykładzie nie zezwalam na atrybuty stylu i tagi. Gdybyś im na to pozwolił, prawdopodobnie chciałbyś przeanalizować CSS i upewnić się, że jest bezpieczny do twoich celów.
Przetestowałem to na kilku nowoczesnych przeglądarkach (Chrome 40, Firefox 36 Beta, IE 11, Chrome na Androida) i na jednej starej (IE 8), aby upewnić się, że wyskoczyło przed wykonaniem jakichkolwiek skryptów. Chciałbym wiedzieć, czy są jakieś przeglądarki, które mają z tym problem, lub jakieś skrajne przypadki, które przeoczę.