Ich muss externe Ressourcen anzeigen, die über domänenübergreifende Anforderungen geladen wurden, und sicherstellen, dass nur " sichere " Inhalte angezeigt werden.
Könnte Prototypen verwenden String # stripScripts verwenden , um Skriptblöcke zu entfernen. Aber Handler wie onclick
oder onerror
sind immer noch da.
Gibt es eine Bibliothek, die das zumindest kann?
- Strip-Skriptblöcke,
- töte DOM-Handler,
- Entfernen Sie Tags auf der schwarzen Liste (z. B.:
embed
oderobject
).
Gibt es also Links und Beispiele zu JavaScript?
javascript
html
security
html-sanitizing
Aemkei
quelle
quelle
Antworten:
Update 2016: Es gibt jetzt ein Google Closure- Paket, das auf dem Caja-Desinfektionsmittel basiert.
Es verfügt über eine übersichtlichere API, wurde neu geschrieben, um APIs zu berücksichtigen, die in modernen Browsern verfügbar sind, und interagiert besser mit Closure Compiler.
Schamloser Plug: Unter caja / plugin / html-sanitizer.js finden Sie einen clientseitigen HTML-Sanitizer, der gründlich überprüft wurde.
Es ist auf der weißen Liste, nicht auf der schwarzen Liste, aber die Whitelists können gemäß CajaWhitelists konfiguriert werden
Wenn Sie alle Tags entfernen möchten, gehen Sie wie folgt vor:
var tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*'; var tagOrComment = new RegExp( '<(?:' // Comment body. + '!--(?:(?:-*[^->])*--+|-?)' // Special "raw text" elements whose content should be elided. + '|script\\b' + tagBody + '>[\\s\\S]*?</script\\s*' + '|style\\b' + tagBody + '>[\\s\\S]*?</style\\s*' // Regular name + '|/?[a-z]' + tagBody + ')>', 'gi'); function removeTags(html) { var oldHtml; do { oldHtml = html; html = html.replace(tagOrComment, ''); } while (html !== oldHtml); return html.replace(/</g, '<'); }
Die Leute werden Ihnen sagen, dass Sie ein Element erstellen
innerHTML
und dasinnerText
oder zuweisen und dann abrufentextContent
und dann Entitäten darin entkommen können. TU das nicht. Es ist anfällig für XSS-Injection, da<img src=bogus onerror=alert(1337)>
deronerror
Handler auch dann ausgeführt wird, wenn der Knoten niemals mit dem DOM verbunden ist.quelle
cssparser.js
, aber was noch wichtiger ist, dashtml4
Objekt). Darüber hinaus verschmutzt es die globalewindow
Eigenschaft. Gibt es eine For-the-Web-Version dieses Codes? Wenn nicht, sehen Sie einen besseren Weg, um eines zu erstellen und zu warten, als ein separates Projekt dafür zu erstellen?Das HTML-Desinfektionsmittel von Google Caja kann "webfähig" gemacht werden, indem es in einen Web-Worker eingebettet wird . Alle vom Desinfektionsprogramm eingeführten globalen Variablen sind im Worker enthalten, und die Verarbeitung erfolgt in einem eigenen Thread.
Für Browser, die Web Worker nicht unterstützen, können wir einen Iframe als separate Umgebung für das Desinfektionsprogramm verwenden. Timothy Chien verfügt über eine Polyfüllung , die genau dies tut und Iframes zur Simulation von Web Workern verwendet, sodass dieser Teil für uns erledigt wird.
Das Caja-Projekt verfügt über eine Wiki-Seite zur Verwendung von Caja als eigenständiges clientseitiges Desinfektionsmittel :
ant
html-sanitizer-minified.js
oderhtml-css-sanitizer-minified.js
in Ihre Seite einhtml_sanitize(...)
Das Arbeiterskript muss nur die folgenden Anweisungen befolgen:
importScripts('html-css-sanitizer-minified.js'); // or 'html-sanitizer-minified.js' var urlTransformer, nameIdClassTransformer; // customize if you need to filter URLs and/or ids/names/classes urlTransformer = nameIdClassTransformer = function(s) { return s; }; // when we receive some HTML self.onmessage = function(event) { // sanitize, then send the result back postMessage(html_sanitize(event.data, urlTransformer, nameIdClassTransformer)); };
(Es wird etwas mehr Code benötigt, um die Simworker-Bibliothek zum Laufen zu bringen, aber für diese Diskussion ist dies nicht wichtig.)
Demo: https://dl.dropbox.com/u/291406/html-sanitize/demo.html
quelle
nameIdClassTransformer
wird für jeden HTML-Namen, jede Element-ID und jede Liste von Klassen aufgerufen. Beim Zurückgebennull
wird das Attribut gelöscht. Durch Bearbeiten der JSON-Dateien in src / com / google / caja / lang / html können Sie auch anpassen, welche Elemente und Attribute in die Whitelist aufgenommen werden.nameIdClassTranformer
obige Funktion ändern, z. B. um alle<script>
Tags abzulehnen und zu akzeptieren<b>
und<i>
Tags?Vertraue niemals dem Kunden. Wenn Sie eine Serveranwendung schreiben, gehen Sie davon aus, dass der Client immer unhygienische, böswillige Daten übermittelt. Es ist eine Faustregel, die Sie vor Ärger bewahrt. Wenn Sie können, würde ich empfehlen, alle Validierungen und Hygienemaßnahmen im Servercode durchzuführen, von denen Sie wissen, dass sie (in angemessenem Maße) nicht zu kurz kommen. Vielleicht könnten Sie eine serverseitige Webanwendung als Proxy für Ihren clientseitigen Code verwenden, der vom Drittanbieter abgerufen und bereinigt wird, bevor er an den Client selbst gesendet wird?
[Bearbeiten] Es tut mir leid, ich habe die Frage falsch verstanden. Ich stehe jedoch zu meinem Rat. Ihre Benutzer sind wahrscheinlich sicherer, wenn Sie den Server bereinigen, bevor Sie ihn an sie senden.
quelle
Jetzt, da alle gängigen Browser Sandbox-Iframes unterstützen, gibt es einen viel einfacheren Weg, den ich für sicher halte . Ich würde es lieben, wenn diese Antwort von Personen überprüft werden könnte, die mit dieser Art von Sicherheitsproblemen besser vertraut sind.
HINWEIS: Diese Methode funktioniert in IE 9 und früheren Versionen definitiv nicht. In dieser Tabelle finden Sie Browserversionen, die Sandboxing unterstützen. (Hinweis: Die Tabelle scheint zu sagen, dass es in Opera Mini nicht funktioniert, aber ich habe es gerade ausprobiert und es hat funktioniert.)
Die Idee ist, einen versteckten Iframe mit deaktiviertem JavaScript zu erstellen, Ihren nicht vertrauenswürdigen HTML-Code einzufügen und ihn analysieren zu lassen. Anschließend können Sie den DOM-Baum durchsuchen und die Tags und Attribute kopieren, die als sicher gelten.
Die hier gezeigten Whitelists sind nur Beispiele. Was am besten zur Whitelist gehört, hängt von der Anwendung ab. Wenn Sie eine komplexere Richtlinie benötigen als nur Whitelists mit Tags und Attributen, kann diese Methode berücksichtigt werden, nicht jedoch dieser Beispielcode.
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; };
Sie können es hier ausprobieren .
Beachten Sie, dass ich in diesem Beispiel Stilattribute und Tags nicht zulasse. Wenn Sie dies zulassen, möchten Sie wahrscheinlich das CSS analysieren und sicherstellen, dass es für Ihre Zwecke sicher ist.
Ich habe dies in mehreren modernen Browsern (Chrome 40, Firefox 36 Beta, IE 11, Chrome für Android) und in einem alten Browser (IE 8) getestet, um sicherzustellen, dass es vor dem Ausführen von Skripten auf Kaution funktioniert. Es würde mich interessieren, ob es Browser gibt, die Probleme damit haben, oder Randfälle, die ich übersehen habe.
quelle
iframe.contentDocument.body.innerHTML = input
, werden alle darin enthaltenen Skript-Tags ausgeführt.sandbox
Attribut abhängen .Sie können nicht jede mögliche seltsame Art von fehlerhaftem Markup vorhersehen, über das ein Browser irgendwo stolpern könnte, um der schwarzen Liste zu entgehen. Es gibt viele weitere Strukturen , die Sie als nur Skript / embed / object und Handler entfernen benötigen.
Versuchen Sie stattdessen, den HTML-Code in Elemente und Attribute in einer Hierarchie zu analysieren, und führen Sie dann alle Element- und Attributnamen für eine möglichst minimale Whitelist aus. Überprüfen Sie auch alle URL-Attribute, die Sie durchgelassen haben, anhand einer Whitelist (denken Sie daran, dass es gefährlichere Protokolle als nur Javascript gibt :).
Wenn die Eingabe gut geformtes XHTML ist, ist der erste Teil der obigen Schritte viel einfacher.
Wenn Sie wie immer bei der HTML-Bereinigung einen anderen Weg finden, dies zu vermeiden, tun Sie dies stattdessen. Es gibt viele, viele mögliche Löcher. Wenn die großen Webmail-Dienste nach so vielen Jahren immer noch Exploits finden, warum glauben Sie dann, dass Sie es besser machen können?
quelle
Es ist also 2016 und ich denke, viele von uns
npm
verwenden jetzt Module in ihrem Code.sanitize-html
scheint die führende Option bei npm zu sein, obwohl es andere gibt .Andere Antworten auf diese Frage liefern einen guten Beitrag dazu, wie Sie Ihre eigenen rollen können. Dies ist jedoch ein Problem, das schwierig genug ist, sodass gut getestete Community-Lösungen wahrscheinlich die beste Antwort sind.
Führen Sie dies in der Befehlszeile aus, um Folgendes zu installieren:
npm install --save sanitize-html
ES5:
var sanitizeHtml = require('sanitize-html'); // ... var sanitized = sanitizeHtml(htmlInput);
ES6:
import sanitizeHtml from 'sanitize-html'; // ... let sanitized = sanitizeHtml(htmlInput);
quelle
[Haftungsausschluss: Ich bin einer der Autoren]
Wir haben dafür eine Open-Source-Bibliothek "nur Web" (dh "erfordert einen Browser") geschrieben, https://github.com/jitbit/HtmlSanitizer , die alle entfernt
tags/attributes/styles
außer den "Whitelist" entfernt.Verwendung:
var input = HtmlSanitizer.SanitizeHtml("<script> Alert('xss!'); </scr"+"ipt>");
PS Funktioniert viel schneller als eine "reine JavaScript" -Lösung, da der Browser zum Parsen und Bearbeiten von DOM verwendet wird. Wenn Sie an einer "reinen JS" -Lösung interessiert sind, versuchen Sie es bitte mit https://github.com/punkave/sanitize-html (nicht verbunden).
quelle
Die oben vorgeschlagene Google Caja-Bibliothek war viel zu komplex, um sie für eine Webanwendung zu konfigurieren und in mein Projekt aufzunehmen (also im Browser ausgeführt). Da wir bereits die CKEditor-Komponente verwenden, habe ich stattdessen auf die integrierte HTML-Bereinigungs- und Whitelist-Funktion zurückgegriffen, die viel einfacher zu konfigurieren ist. Sie können also eine CKEditor-Instanz in einen versteckten Iframe laden und Folgendes tun:
CKEDITOR.instances['myCKEInstance'].dataProcessor.toHtml(myHTMLstring)
Wenn Sie CKEditor in Ihrem Projekt nicht verwenden, ist dies möglicherweise ein Overkill, da die Komponente selbst etwa ein halbes Megabyte (minimiert) beträgt. Wenn Sie jedoch über die Quellen verfügen, können Sie den Code möglicherweise isolieren die Whitelist (
CKEDITOR.htmlParser
?) und machen es viel kürzer.http://docs.ckeditor.com/#!/api
http://docs.ckeditor.com/#!/api/CKEDITOR.htmlDataProcessor
quelle
Ich empfehle, Frameworks aus Ihrem Leben herauszuschneiden, da dies Ihnen auf lange Sicht die Dinge übermäßig erleichtern würde.
cloneNode: Das Klonen eines Knotens kopiert alle seine Attribute und deren Werte, kopiert jedoch KEINE Ereignis-Listener .
https://developer.mozilla.org/en/DOM/Node.cloneNode
Das Folgende wird nicht getestet, obwohl ich seit einiger Zeit Treewalker verwende und sie einer der am meisten unterbewerteten Teile von JavaScript sind. Hier ist eine Liste der Knotentypen, die Sie crawlen können . Normalerweise verwende ich SHOW_ELEMENT oder SHOW_TEXT .
http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html#Traversal-NodeFilter
function xhtml_cleaner(id) { var e = document.getElementById(id); var f = document.createDocumentFragment(); f.appendChild(e.cloneNode(true)); var walker = document.createTreeWalker(f,NodeFilter.SHOW_ELEMENT,null,false); while (walker.nextNode()) { var c = walker.currentNode; if (c.hasAttribute('contentEditable')) {c.removeAttribute('contentEditable');} if (c.hasAttribute('style')) {c.removeAttribute('style');} if (c.nodeName.toLowerCase()=='script') {element_del(c);} } alert(new XMLSerializer().serializeToString(f)); return f; } function element_del(element_id) { if (document.getElementById(element_id)) { document.getElementById(element_id).parentNode.removeChild(document.getElementById(element_id)); } else if (element_id) { element_id.parentNode.removeChild(element_id); } else { alert('Error: the object or element \'' + element_id + '\' was not found and therefore could not be deleted.'); } }
quelle