Мне нужно отображать внешние ресурсы, загруженные через междоменные запросы, и убедиться, что отображается только « безопасный » контент.
Можно использовать Prototype String # stripScripts для удаления блоков скрипта. Но такие обработчики как onclick
или onerror
все еще существуют.
Есть ли какая-нибудь библиотека, которая может хотя бы
- убрать блоки сценария,
- убить обработчики DOM,
- удалить теги из черного списка (например:
embed
илиobject
).
Так есть ли какие-нибудь ссылки и примеры по JavaScript?
Ответы:
Обновление 2016: теперь существует пакет Google Closure на основе дезинфицирующего средства Caja.
Он имеет более чистый API, был переписан с учетом API, доступных в современных браузерах, и лучше взаимодействует с Closure Compiler.
Бесстыдный плагин: см. Caja / plugin / html-sanitizer.js, чтобы узнать о дезинфицирующем средстве на стороне клиента, которое было тщательно проверено.
Он внесен в белый список, а не в черный, но белые списки настраиваются в соответствии с CajaWhitelists
Если вы хотите удалить все теги, сделайте следующее:
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, '<'); }
Люди скажут вам, что вы можете создать элемент и назначить,
innerHTML
а затем получитьinnerText
илиtextContent
, а затем избежать сущностей в нем. Не делай этого. Он уязвим для внедрения XSS, поскольку<img src=bogus onerror=alert(1337)>
будет запускатьonerror
обработчик, даже если узел никогда не присоединен к DOM.источник
cssparser.js
, но, что более важно,html4
объекта). Кроме того, это загрязняет глобальнуюwindow
собственность. Есть ли версия этого кода для Интернета? Если нет, видите ли вы лучший способ создать и поддерживать его, чем создавать для него отдельный проект?Дезинфицирующее средство Google Caja HTML можно сделать "готовым к работе в сети ", встроив его в веб-воркер . Любые глобальные переменные, введенные дезинфицирующим средством, будут содержаться внутри рабочего, плюс обработка происходит в его собственном потоке.
Для браузеров, которые не поддерживают Web Workers, мы можем использовать iframe как отдельную среду для работы sanitizer. Timothy Chien имеет полифил, который делает именно это, используя iframe для имитации Web Workers, так что эта часть сделана за нас.
У проекта Caja есть вики-страница о том, как использовать Caja в качестве автономного средства очистки на стороне клиента :
ant
html-sanitizer-minified.js
илиhtml-css-sanitizer-minified.js
на свою страницуhtml_sanitize(...)
Рабочий скрипт должен только следовать этим инструкциям:
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)); };
(Для работы библиотеки simworker требуется немного больше кода, но это не важно для данного обсуждения.)
Демо: https://dl.dropbox.com/u/291406/html-sanitize/demo.html
источник
nameIdClassTransformer
вызывается для каждого имени HTML, идентификатора элемента и списка классов; возвратnull
удалит атрибут. Редактируя файлы JSON в src / com / google / caja / lang / html, вы также можете настроить, какие элементы и атрибуты будут добавлены в белый список.nameIdClassTranformer
указанную выше функцию, например, чтобы отклонить все<script>
теги и принять<b>
и<i>
теги?Никогда не доверяйте клиенту. Если вы пишете серверное приложение, предполагайте, что клиент всегда будет отправлять антисанитарные вредоносные данные. Это практическое правило, которое убережет вас от неприятностей. Если можете, я бы посоветовал провести всю проверку и санацию в коде сервера, который, как вы знаете (в разумной степени), не будет возиться. Возможно, вы могли бы использовать серверное веб-приложение в качестве прокси для вашего клиентского кода, который извлекается от третьей стороны и выполняет очистку перед отправкой самому клиенту?
[править] Простите, я неправильно понял вопрос. Однако я верю своему совету. Ваши пользователи, вероятно, будут в большей безопасности, если вы продезинфицируете сервер перед его отправкой им.
источник
Теперь, когда все основные браузеры поддерживают изолированные фреймы 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); // 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), чтобы убедиться, что он вышел из строя перед выполнением любых скриптов. Мне было бы интересно узнать, есть ли какие-либо браузеры, у которых есть проблемы с этим, или какие-либо крайние случаи, которые я упускаю.
источник
iframe.contentDocument.body.innerHTML = input
, все теги сценария будут выполнены.sandbox
атрибута.Вы не можете предвидеть все возможные странные типы искаженной разметки, которые какой-то браузер где-то может споткнуться, чтобы избежать черного списка, поэтому не заносите в черный список. Есть много больше структур Вы , возможно , потребуется удалить , чем просто скрипт / вставлять / объекта и обработчиков.
Вместо этого попытайтесь разобрать HTML на элементы и атрибуты в иерархии, а затем запустить все имена элементов и атрибутов в минимально возможном белом списке. Также проверьте все пропущенные атрибуты URL-адресов в белом списке (помните, что существуют более опасные протоколы, чем просто javascript :).
Если ввод - это правильно сформированный XHTML, первая часть вышеизложенного намного проще.
Как всегда с дезинфекцией HTML, если вы можете найти другой способ избежать этого, сделайте это. Есть очень много потенциальных ям. Если основные службы веб-почты по прошествии многих лет все еще находят уязвимости, почему вы думаете, что можете добиться большего?
источник
Итак, это 2016 год, и я думаю, что многие из нас сейчас используют
npm
модули в нашем коде.sanitize-html
кажется ведущим вариантом в npm, хотя есть и другие .Другие ответы на этот вопрос дают большой вклад в то, как свернуть свой собственный, но это достаточно сложная проблема, и хорошо протестированные решения сообщества, вероятно, являются лучшим ответом.
Запустите это в командной строке для установки:
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);
источник
[Отказ от ответственности: я один из авторов]
Для этого мы написали библиотеку с открытым исходным кодом «только для Интернета» (т.е. «требуется браузер») https://github.com/jitbit/HtmlSanitizer, которая удаляет все,
tags/attributes/styles
кроме «белых».Применение:
var input = HtmlSanitizer.SanitizeHtml("<script> Alert('xss!'); </scr"+"ipt>");
PS Работает намного быстрее, чем решение «на чистом JavaScript», поскольку оно использует браузер для анализа и управления DOM. Если вас интересует "чистое JS" решение, попробуйте https://github.com/punkave/sanitize-html (не аффилированный)
источник
Предложенная выше библиотека Google Caja была слишком сложной для настройки и включения в мой проект веб-приложения (то есть, работающего в браузере). Вместо этого, поскольку мы уже используем компонент CKEditor, я прибег к использованию встроенной функции очистки HTML и внесения в белый список, которую гораздо проще настроить. Итак, вы можете загрузить экземпляр CKEditor в скрытый iframe и сделать что-то вроде:
CKEDITOR.instances['myCKEInstance'].dataProcessor.toHtml(myHTMLstring)
Конечно, если вы не используете CKEditor в своем проекте, это может быть немного излишним, поскольку размер самого компонента составляет около половины мегабайта (минимизирован), но если у вас есть исходники, возможно, вы можете изолировать код, выполняющий белый список (
CKEDITOR.htmlParser
?) и сделать его намного короче.http://docs.ckeditor.com/#!/api
http://docs.ckeditor.com/#!/api/CKEDITOR.htmlDataProcessor
источник
Я рекомендую исключить рамки из вашей жизни, это значительно упростит вам жизнь в долгосрочной перспективе.
cloneNode: при клонировании узла копируются все его атрибуты и их значения, но это НЕ копировать слушатель событий .
https://developer.mozilla.org/en/DOM/Node.cloneNode
Следующее не тестировалось, хотя я уже некоторое время использую Treewalkers, и они являются одной из самых недооцененных частей JavaScript. Вот список типов узлов, которые вы можете сканировать, обычно я использую SHOW_ELEMENT или 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.'); } }
источник