2013-07-17 2 views
5

신뢰할 수있는 사용자의 HTML을 받아 들일 수 있기를 원하며 내 웹 사이트의 페이지에 안전하게 포함시킬 수 있기를 바랍니다. 이 같은 <script> 또는 <iframe> 위험한 태그를 포함하지 않는 한이에 의해 내가 마크 업이 제거 또는 탈출하지만, 본질적으로 변하지을 통과해야한다는 안된다는 것을 의미합니다, 같은 onload, 또는 배경의 URL 위험한 CSS 속성 위험한 속성. (일부 이전 IE는 CSS에서 자바 스크립트 URL을 실행합니다.)신뢰할 수없는 HTML5 살생

iframe에 포함 된 다른 도메인에서 콘텐츠를 제공하는 것은 좋은 방법이 아닙니다. iframe의 높이를 미리 알려줄 방법이 없기 때문입니다. 항상 일부 페이지에서는보기가 어려울 것입니다.

나는 HTML 정수기로보고 있지만, 아직 HTML5를 지원하지 않는 것 같습니다. 또한 Google Caja를 살펴 보았지만 스크립트를 사용하지 않는 솔루션을 찾고 있습니다.

누구든지이 작업을 수행 할 라이브러리를 알고 있습니까? PHP가 선호되지만 거지는 선택자가 될 수 없습니다.

+0

[raxan data sanitizer] (https://searchcode.com/codesearch/view/2955473/) – Gunaseelan

+2

도구, 라이브러리 또는 좋아하는 오프 사이트 리소스를 추천 해달라고 요청하는 질문은 스택 오버플로는 해설 된 답변과 스팸을 끌어 들이기 쉽습니다. 대신 문제를 설명하고 지금까지 해결 된 문제를 설명하십시오. –

답변

2

당신의 라인을 따라 뭔가를 할 수 있습니다 다시

preg_replace('/<\s*iframe\s+[^>]*>.*<\s*\/\s*iframe\s+[^>]*>/i', '', $html); 
preg_replace('/<\s*script\s+[^>]*>.*<\s*\/\s*script\s+[^>]*>/i', '', $html); 
preg_replace('/\s+onload\s+=\s+"[^"]+"/i', '', $html); 

:하지만 ... 당신은 지금 당신이 두 가지 문제를 가지고, 정규 표현식에이 -이 원하는 것보다 더 제거 할 수 있으며보다 더두고 싶었어.

그러나 HTML 정수기는 가장 현대적이고 적합 (오픈 소스) 프로젝트가 계속 한 것을 사용하고 당신이 정말로 필요할 경우 어쩌면 조정을해야한다 아마도 이후

.

당신은뿐만 아니라 다음 중 하나를 확인하실 수 있습니다 :

  • kses - 더 개발 kses
  • PHP Input Filter - - 필터링 할 수 있습니다 사실상의 표준을, 워드 프레스에 방법뿐만 아니라
  • htmLawed 발견 태그 및 속성

자신의 페이지 레이아웃이 해상도를 포함하지 않도록해야하지만 태그가 닫히지 않았기 때문입니다.

2

어쩌면 다른 접근 방법을 사용하는 것이 좋습니다. 어떻게 사용할 수 있는지 알려주시겠습니까?

이 경우에는 사용 strip_tags를 사용할 수 있습니다. 이 방법은 훨씬 쉽고 훨씬 더 많이 제어 할 수 있습니다. 앞으로도 매우 쉽게 확장 할 수 있습니다.

+1

>이 함수는 allowable_tags를 사용하여 허용하는 태그의 속성을 수정하지 않습니다. 다른 사용자에게 표시 될 텍스트를 게시 할 때 악의적 인 사용자가 남용 할 수있는 style 및 onmouseover 속성을 포함합니다. – Brian

6

검은 리스팅 접근법은 업그레이드를 요구합니다. 따라서 브라우저가 새로운 표준을 지원하기 시작할 때마다 반드시 위생 도구를 같은 수준으로 그려야합니다. 이러한 변화는 생각보다 자주 발생합니다. 원인의 (잘 정의 된 예외 strip_tags에 의해 달성된다)

화이트리스트는 사용자를위한 옵션을 축소하지만, 저장 사이트에 당신을 넣습니다. 내 자신의 사이트에

I (예 : 관리자)를 매우 신뢰할 수있는 사용자를위한 페이지에 검은 색 목록을 적용 할 수있는 정책과 다른 모든 페이지의 화이트리스트를 가지고있다. 그것은 검은 리스팅에 많은 노력을 기울이지 않는 입장으로 나를 설정합니다. 더 성숙한 역할 & 허가 개념을 사용하면 블랙리스트와 화이트리스트를 미세하게 분류 할 수 있습니다.


UPDATE :

내가 태그 수준에 화이트리스트를 strip_tags하지만 속성에 대한 모든 것을 받아 들일 않는 점을 가지고 : 나는 당신이 찾는 것 같아요 수평. 흥미롭게도 HTMLpurifier는 속성 수준에서 화이트리스트를 작성하는 것으로 보입니다. 고마워, 여기 좋은 학습이었다.

+2

'strip_tags'는 위험한 속성으로부터 보호 할 수 없습니다. 태그가 허용되는 한 태그는 속성을 전혀 건드리지 않습니다. – Brian

2

Ruby에서 HTML 콘텐츠를 구문 분석하기 위해 Nokogiri (php version)을 사용하고 있습니다. 사용자의 데이터를 구문 분석하고 불필요한 태그 또는 속성을 제거한 다음 텍스트로 변환 할 수 있습니다.

phpQuery - 다른 파서.

PHP에는 strip_tags 기능이 있습니다.

아니면 수동으로 실시 모든 속성을 제거 할 수는 :

$dom = new DOMDocument; 
$dom -> loadHTML($html); 
$xpath = new DOMXPath($dom); 
$nodes = $xpath -> query("//*[@style]"); // all elements with style attribute 
foreach ($nodes as $node) { 
    // remove or do what you want 
    $node -> removeAttribute("style"); 
} 
echo $dom -> saveHTML(); 
+0

DOMDocument는 HTML5에서 작동합니까? – Brian

+0

@ 브라이언 그는 일을하고 있지만 좋지 않습니다. 더 나은 사용 https://github.com/html5lib/html5lib-php – ostapische

1

WdHTMLParser 클래스를 참조하십시오. 이 수업을 내 포럼에 사용합니다. WdHTMLParser와

샘플 :

이 클래스가 배열에 HTML을 구문 분석 :

<div> 
    <span> 
     <br /> 
     <span> 
     un bout de texte 
     </span> 
     <input type="text" /> 
    </span> 
</div> 

배열 :

Array (
[0] => Array (
    [name] => div 
    [args] => Array() 
    [children] => Array (
    [0] => Array (
    [name] => span 
    [args] => Array() 
    [children] => Array (
    [0] => Array (
     [name] => br 
     [args] => Array() 
    ) 
    [1] => Array (
     [name] => span 
     [args] => Array() 
     [children] => Array (
     [0] => un bout de texte 
    ) 
    ) 
    [2] => Array (
     [name] => input 
     [args] => Array (
     [type] => text 
    ) 
    ) 
    ) 
    ) 
) 
) 
) 

WdHTMLParser 배열이 HTML로는

난에이 클래스를 사용 배열을 HTML로 변환하는 내 웹 사이트.

  • voyageWdHTML_allowattr :은 이러한 속성은 허용됩니다.

  • voyageWdHTML_allowtag : 이러한 태그가 허용됩니다.

  • voyageWdHTML_special : 나만의 규칙을 만드십시오. 사실, 각 링크에 "_blank"를 추가합니다. 그리고 나서 <br>으로 바꾸고 새 태그 (\ n)을 사전 태그로 사용하십시오.

  • fix_javascript :이 기능을 활성화/비활성화 할 수는 있지만 쓸모가 없습니다.

샘플 PHP :

<?php 
include "WdHTMLParser.php"; 
include "parser.php"; 

list($erreur, $message) = (new Parser())->parseBadHTML("<div> 
    <span> 
     <a onclick=\"alert('Hacked ! :'(');\">Check javascript</a> 
     <script>alert(\"lol\");</script> 
    </span> 
</div>"); 

if ($erreur) { 
    die("Error : ".$message); 
} 

echo $message; 

출력 :

<div> 
    <span> 
     <a target="_blank">Check javascript</a> 
     <pre>alert("lol");</pre> 
    </span> 
</div> 

내 파서 클래스 :

<?php 
class Parser { 
    //private function fix_javascript(&$message) { } 

    private function voyageWdHTML_args($tab_args, $objname) { 
     $html = ""; 
     foreach ($tab_args as $attr => $valeur) { 
      if ($valeur !== null && $this->voyageWdHTML_allowattr($attr)) { 
       $html .= " $attr=\"".htmlentities($valeur)."\""; 
      } 
     } 
     return $html; 
    } 

    private function voyageWdHTML_allowattr($attr) { 
     return in_array($attr, array("align", "face", "size", "href", "title", "target", "src", "color", "style", 
            "data-class", "data-format")); 
    } 

    private function voyageWdHTML_allowtag($name) { 
     return in_array($name, array("br", "b", "i", "u", "strike", "sub", "sup", "div", "ol", "ul", "li", "font", "span", "code", 
            "hr", "blockquote", "cite", "a", "img", "p", "pre", "h6", "h5", "h4", "h3", "h2", "h1")); 
    } 

    private function voyageWdHTML_special(&$obj) { 
     if ($obj["name"] == "a") { $obj["args"]["target"] = "_blank"; } 
     if ($obj["name"] == "pre") { 
      array_filter($obj["children"], function (&$var) { 
       if (is_string($var)) { return true; } 
       if ($var["name"] == "br") { $var = "\n"; return true; } 
       return false; 
      }); 
     } 
    } 

    private function voyageWdHTML($tableau, $lvl = 0) { 
     $html = ""; 
     foreach ($tableau as $obj) { 
      if (is_array($obj)) { 
       if (!$this->voyageWdHTML_allowtag($obj["name"])) { 
        $obj["name"] = "pre"; 
        if (!isset($obj["children"])) { 
         $obj["children"] = array(); 
        } 
       } 
       if (isset($obj["children"])) { 
        $this->voyageWdHTML_special($obj); 
        $html .= "<{$obj["name"]}{$this->voyageWdHTML_args($obj["args"], $obj["name"])}>{$this->voyageWdHTML($obj["children"], $lvl+1)}</{$obj["name"]}>"; 
       } else { 
        $html .= "<{$obj["name"]}>"; 
       } 
      } else { 
       $html .= $obj; 
      } 
     } 
     return $html; 
    } 

    public function parseBadHTML($message) { 
     $WdHTMLParser = new WdHTMLParser(); 
     $message = str_replace(array("<br>", "<hr>"), array("<br/>", "<hr/>"), $message); 
     $tableau = $WdHTMLParser->parse($message); 

     if ($WdHTMLParser->malformed) { 
      $retour = $WdHTMLParser->error; 
     } else { 
      $retour = $this->voyageWdHTML($tableau); 

      //$this->fix_javascript($retour);// To make sur 
     } 

     return array($WdHTMLParser->malformed, $retour); 
    } 
} 

,363,210

WdHTMLParser 클래스는

<?php 
class WdHTMLParser { 
    private $encoding; 
    private $matches; 
    private $escaped; 
    private $opened = array(); 
    public $malformed; 
    public function parse($html, $namespace = NULL, $encoding = 'utf-8') { 
     $this->malformed = false; 
     $this->encoding = $encoding; 
     $html   = $this->escapeSpecials($html); 
     $this->matches = preg_split('#<(/?)' . $namespace . '([^>]*)>#', $html, -1, PREG_SPLIT_DELIM_CAPTURE); 
     $tree   = $this->buildTree(); 
     if ($this->escaped) { 
      $tree = $this->unescapeSpecials($tree); 
     } 
     return $tree; 
    } 
    private function escapeSpecials($html) { 
     $html = preg_replace_callback('#<\!--.+-->#sU', array($this, 'escapeSpecials_callback'), $html); 
     $html = preg_replace_callback('#<\?.+\?>#sU', array($this, 'escapeSpecials_callback'), $html); 
     return $html; 
    } 
    private function escapeSpecials_callback($m) { 
     $this->escaped = true; 
     $text   = $m[0]; 
     $text   = str_replace(array('<', '>'), array("\x01", "\x02"), $text); 
     return $text; 
    } 
    private function unescapeSpecials($tree) { 
     return is_array($tree) ? array_map(array($this, 'unescapeSpecials'), $tree) : str_replace(array("\x01", "\x02"), array('<', '>'), $tree); 
    } 
    private function buildTree() { 
     $nodes = array(); 
     $i  = 0; 
     $text = NULL; 
     while (($value = array_shift($this->matches)) !== NULL) { 
      switch ($i++ % 3) { 
       case 0: { 
        if (trim($value)) { 
         $nodes[] = $value; 
        } 
       } 
        break; 
       case 1: { 
        $closing = ($value == '/'); 
       } 
        break; 
       case 2: { 
        if (substr($value, -1, 1) == '/') { 
         $nodes[] = $this->parseMarkup(substr($value, 0, -1)); 
        } else if ($closing) { 
         $open = array_pop($this->opened); 
         if ($value != $open) { 
          $this->error($value, $open); 
         } 
         return $nodes; 
        } else { 
         $node    = $this->parseMarkup($value); 
         $this->opened[] = $node['name']; 
         $node['children'] = $this->buildTree($this->matches); 
         $nodes[]   = $node; 
        } 
       } 
      } 
     } 
     return $nodes; 
    } 
    public function parseMarkup($markup) { 
     preg_match('#^[^\s]+#', $markup, $matches); 
     $name = $matches[0]; 
     preg_match_all('#\s+([^=]+)\s*=\s*"([^"]+)"#', $markup, $matches, PREG_SET_ORDER); 
     $args = array(); 
     foreach ($matches as $m) { 
      $args[$m[1]] = html_entity_decode($m[2], ENT_QUOTES, $this->encoding); 
     } 
     return array('name' => $name, 'args' => $args); 
    } 
    public function error($markup, $expected) { 
     $this->malformed = true; 
     printf('unexpected closing markup "%s", should be "%s"', $markup, $expected); 
    } 
} 

는 쉬르을 사용하려면이 기능 (mybb.com)를 사용할 수 있습니다 : 내가 결정

<?php 
class Parser { 
    private function fix_javascript(&$message) { 
     $js_array = array(
      "#(&\#(0*)106;?|&\#(0*)74;?|&\#x(0*)4a;?|&\#x(0*)6a;?|j)((&\#(0*)97;?|&\#(0*)65;?|a)(&\#(0*)118;?|&\#(0*)86;?|v)(&\#(0*)97;?|&\#(0*)65;?|a)(\s)?(&\#(0*)115;?|&\#(0*)83;?|s)(&\#(0*)99;?|&\#(0*)67;?|c)(&\#(0*)114;?|&\#(0*)82;?|r)(&\#(0*)105;?|&\#(0*)73;?|i)(&\#112;?|&\#(0*)80;?|p)(&\#(0*)116;?|&\#(0*)84;?|t)(&\#(0*)58;?|\:))#i", 
      "#(o)(nmouseover\s?=)#i", 
      "#(o)(nmouseout\s?=)#i", 
      "#(o)(nmousedown\s?=)#i", 
      "#(o)(nmousemove\s?=)#i", 
      "#(o)(nmouseup\s?=)#i", 
      "#(o)(nclick\s?=)#i", 
      "#(o)(ndblclick\s?=)#i", 
      "#(o)(nload\s?=)#i", 
      "#(o)(nsubmit\s?=)#i", 
      "#(o)(nblur\s?=)#i", 
      "#(o)(nchange\s?=)#i", 
      "#(o)(nfocus\s?=)#i", 
      "#(o)(nselect\s?=)#i", 
      "#(o)(nunload\s?=)#i", 
      "#(o)(nkeypress\s?=)#i" 
     ); 

     $message = preg_replace($js_array, "$1<b></b>$2$4", $message); 
    } 
} 
0

을 그냥 html5lib - 파이썬을 사용합니다. 이것은 내가 생각 해낸 것입니다 :

#!/usr/bin/env python 
import sys 
from xml.dom.minidom import Node 
import html5lib 
from html5lib import (HTMLParser, sanitizer, serializer, treebuilders, 
        treewalkers) 

parser = HTMLParser(tokenizer=sanitizer.HTMLSanitizer, 
        tree=treebuilders.getTreeBuilder("dom")) 
serializer = serializer.htmlserializer.HTMLSerializer(omit_optional_tags=False) 

document = parser.parse(sys.stdin.read(), encoding="utf-8") 
# find the <html> node 
for child in document.childNodes: 
    if child.nodeType == Node.ELEMENT_NODE and child.nodeName == 'html': 
     htmlNode = child 
# find the <body> node 
for child in htmlNode.childNodes: 
    if child.nodeType == Node.ELEMENT_NODE and child.nodeName == 'body': 
     bodyNode = child 
# serialize all children of the <body> node 
for child in bodyNode.childNodes: 
    stream = treewalkers.getTreeWalker("dom")(child) 
    sys.stdout.write(serializer.render(stream, encoding="utf-8")) 

예 입력 :

<script>alert("hax")</script> 
<p onload="alert('this is a dangerous attribute')"><b>hello,</b> world</p> 

예 출력 :

http://htmlpurifier.org/docs : 나는 개인적으로이 정확한 목적을 위해 HTML 정수기를 사용

&lt;script&gt;alert("hax")&lt;/script&gt; 
<p><b>hello,</b> world</p> 
+0

편집 : 이것은 파이썬 2에서만 작동합니다. 파이썬 3에서도 작동하는 버전이 있습니다.하지만 조금 hackish하기 때문에 게시하지 않을 것입니다. . – Brian

0

잘 작동하며 모든 태그와 속성을 사용자 정의 할 수 있습니다. 지금까지이 플러그인에 보안 문제가 없었습니다.

+0

HTML 정수기가 아직 HTML5를 지원하지 않습니다. – Brian

+0

그러나 자신의 태그와 속성을 정의 할 수 있습니다. – morissette

+0

다음은 예입니다. https://gist.github.com/lluchs/3303693 – morissette