development

클라이언트 측에서 HTML 삭제 / 재 작성

big-blog 2020. 10. 28. 08:23
반응형

클라이언트 측에서 HTML 삭제 / 재 작성


교차 도메인 요청을 통해로드 된 외부 리소스를 표시하고 " 안전한 "콘텐츠 만 표시해야 합니다.

Prototype의 String # stripScripts 를 사용하여 스크립트 블록을 제거 할 수 있습니다 . 그러나 onclick또는 같은 핸들러 onerror는 여전히 존재합니다.

적어도 할 수있는 도서관이 있습니까?

  • 스트립 스크립트 블록,
  • DOM 핸들러를 죽이고,
  • 검은 색으로 나열된 태그를 제거합니다 (예 : embed또는 object).

그렇다면 JavaScript 관련 링크와 예제가 있습니까?


2016 업데이트 : 이제 Caja 새니 타이 저를 기반으로 하는 Google Closure 패키지가 있습니다.

더 깨끗한 API를 가지고 있으며 최신 브라우저에서 사용할 수있는 API를 고려하여 다시 작성되었으며 Closure Compiler와 더 잘 상호 작용합니다.


뻔뻔한 플러그 : 철저하게 검토 된 클라이언트 측 html 새니 타이 저는 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, '&lt;');
}

사람들은 당신이 요소를 생성하고 할당 할 수 있음을 알려드립니다 innerHTML다음을 얻을 innerText또는 textContent점에서 엔티티를하고 탈출. 그거 하지마. 노드가 DOM에 연결되지 않은 경우에도 핸들러 <img src=bogus onerror=alert(1337)>를 실행 하므로 XSS 주입에 취약합니다 onerror.


Google Caja HTML 새니 타이 저는 웹 워커 에 삽입하여 '웹 지원'으로 만들 수 있습니다 . 새니 타이 저에 의해 도입 된 모든 전역 변수는 작업자 내에 포함되며 자체 스레드에서 처리가 수행됩니다.

웹 워커를 지원하지 않는 브라우저의 경우 새니 타이 저가 작동 할 별도의 환경으로 iframe을 사용할 수 있습니다. Timothy Chien에는 웹 워커를 시뮬레이션하기 위해 iframe을 사용하여이 부분을 수행 하는 폴리 필 이 있습니다.

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));
};

(심 워커 라이브러리를 작동 시키려면 더 많은 코드가 필요하지만이 토론에서는 중요하지 않습니다.)

데모 : https://dl.dropbox.com/u/291406/html-sanitize/demo.html


클라이언트를 신뢰하지 마십시오. 서버 애플리케이션을 작성하는 경우 클라이언트가 항상 비위생적 인 악성 데이터를 제출한다고 가정합니다. 그것은 당신을 문제로부터 지켜줄 경험의 법칙입니다. 가능한 경우 서버 코드에서 모든 유효성 검사 및 위생 처리를 수행하는 것이 좋습니다. 서버 측 웹 애플리케이션을 클라이언트 측 코드의 프록시로 사용할 수 있습니다. 클라이언트 측 코드는 제 3 자에서 가져 와서 클라이언트 자체로 보내기 전에 위생 처리를 수행합니다.

죄송합니다. 질문을 오해했습니다. 그러나 나는 나의 충고를지지한다. 사용자에게 보내기 전에 서버에서 살균하면 사용자가 더 안전 할 것입니다.


어떤 브라우저가 블랙리스트를 벗어나기 위해 어딘가에 넘어갈 수있는 모든 이상한 유형의 잘못된 마크 업을 예상 할 수는 없으므로 블랙리스트에 올리지 마십시오. 스크립트 / 임베딩 / 객체 및 처리기보다 제거해야 할 구조 많습니다 .

대신 HTML을 계층 구조의 요소 및 속성으로 구문 분석 한 다음 가능한 최소 허용 목록에 대해 모든 요소 및 속성 이름을 실행하십시오. 또한 허용 한 URL 속성을 허용 목록과 비교하여 확인하십시오 (JavaScript :보다 더 위험한 프로토콜이 있음을 기억하십시오).

입력이 잘 구성된 XHTML이면 위의 첫 번째 부분이 훨씬 쉽습니다.

항상 HTML 삭제를 피할 수있는 다른 방법을 찾을 수 있다면 대신 그렇게하십시오. 많은 잠재적 인 구멍이 있습니다. 몇 년이 지난 후에도 주요 웹 메일 서비스가 여전히 악용을 발견하고 있다면 무엇이 더 잘할 수 있다고 생각합니까?


이제 모든 주요 브라우저 샌드 박스 iframe을 지원하는, 내가하는 훨씬 간단한 방법이 생각 안전 할 수는. 이런 종류의 보안 문제에 더 익숙한 사람들이이 답변을 검토 할 수 있다면 좋겠습니다.

참고 :이 방법은 IE 9 및 이전 버전에서는 작동하지 않습니다. 샌드 박싱을 지원하는 브라우저 버전 이 표참조하십시오 . (참고 : 표에는 Opera Mini에서 작동하지 않는다고 표시되어 있지만 방금 시도했지만 작동했습니다.)

아이디어는 JavaScript가 비활성화 된 숨겨진 iframe을 만들고 신뢰할 수없는 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를 구문 분석하고 목적에 맞는지 확인하고 싶을 것입니다.

I've tested this on several modern browsers (Chrome 40, Firefox 36 Beta, IE 11, Chrome for Android), and on one old one (IE 8) to make sure it bailed before executing any scripts. I'd be interested to know if there are any browsers that have trouble with it, or any edge cases that I'm overlooking.


So, it's 2016, and I think many of us are using npm modules in our code now. sanitize-html seems like the leading option on npm, though there are others.

Other answers to this question provide great input in how to roll your own, but this is a tricky enough problem that well-tested community solutions are probably the best answer.

Run this on the command line to install: 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);


String.prototype.sanitizeHTML=function (white,black) {
   if (!white) white="b|i|p|br";//allowed tags
   if (!black) black="script|object|embed";//complete remove tags
   var e=new RegExp("(<("+black+")[^>]*>.*</\\2>|(?!<[/]?("+white+")(\\s[^<]*>|[/]>|>))<[^<>]*>|(?!<[^<>\\s]+)\\s[^</>]+(?=[/>]))", "gi");
   return this.replace(e,"");
}

-black list -> complete remove tag and content

-white list -> retain tags

-other tags are removed but tag content is retained

-all attributes of white list tag's (the remaining ones) are removed


The Google Caja library suggested above was way too complex to configure and include in my project for a Web application (so, running on the browser). What I resorted to instead, since we already use the CKEditor component, is to use it's built-in HTML sanitizing and whitelisting function, which is far more easier to configure. So, you can load a CKEditor instance in a hidden iframe and do something like:

CKEDITOR.instances['myCKEInstance'].dataProcessor.toHtml(myHTMLstring)

Now, granted, if you're not using CKEditor in your project this may be a bit of an overkill, since the component itself is around half a megabyte (minimized), but if you have the sources, maybe you can isolate the code doing the whitelisting (CKEDITOR.htmlParser?) and make it much shorter.

http://docs.ckeditor.com/#!/api

http://docs.ckeditor.com/#!/api/CKEDITOR.htmlDataProcessor


[Disclaimer: I'm one of the authors]

We wrote a "web-only" (i.e. "requires a browser") open source library for this, https://github.com/jitbit/HtmlSanitizer that removes all tags/attributes/styles except the "whitelisted" ones.

Usage:

var input = HtmlSanitizer.SanitizeHtml("<script> Alert('xss!'); </scr"+"ipt>");

P.S. Works much faster than a "pure JavaScript" solution since it uses the browser to parse and manipulate DOM. If you're interested in a "pure JS" solution please try https://github.com/punkave/sanitize-html (not affiliated)


I recommend cutting frameworks out of your life, it would make things excessively easier for you in the long term.

cloneNode: Cloning a node copies all of its attributes and their values but does NOT copy event listeners.

https://developer.mozilla.org/en/DOM/Node.cloneNode

The following is not tested though I have using treewalkers for some time now and they are one of the most undervalued parts of JavaScript. Here is a list of the node types you can crawl, usually I use SHOW_ELEMENT or 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.');
 }
}

참고URL : https://stackoverflow.com/questions/295566/sanitize-rewrite-html-on-the-client-side

반응형