2009-09-04 63 views
3

我想允许很多用户提交用户配置文件的html,我目前试图过滤出我不想要的内容,但我现在想要更改并使用白名单方法。允许用户在PHP中提交HTML

这里是我当前的非白名单的方式

function FilterHTML($string) { 
    if (get_magic_quotes_gpc()) { 
     $string = stripslashes($string); 
    } 
    $string = html_entity_decode($string, ENT_QUOTES, "ISO-8859-1"); 
    // convert decimal 
    $string = preg_replace('/&#(\d+)/me', "chr(\\1)", $string); // decimal notation 
    // convert hex 
    $string = preg_replace('/&#x([a-f0-9]+)/mei', "chr(0x\\1)", $string); // hex notation 
    //$string = html_entity_decode($string, ENT_COMPAT, "UTF-8"); 
    $string = preg_replace('#(&\#*\w+)[\x00-\x20]+;#U', "$1;", $string); 
    $string = preg_replace('#(<[^>]+[\s\r\n\"\'])(on|xmlns)[^>]*>#iU', "$1>", $string); 
    //$string = preg_replace('#(&\#x*)([0-9A-F]+);*#iu', "$1$2;", $string); //bad line 
    $string = preg_replace('#/*\*()[^>]*\*/#i', "", $string); // REMOVE /**/ 
    $string = preg_replace('#([a-z]*)[\x00-\x20]*([\`\'\"]*)[\\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iU', '...', $string); //JAVASCRIPT 
    $string = preg_replace('#([a-z]*)([\'\"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iU', '...', $string); //VBSCRIPT 
    $string = preg_replace('#([a-z]*)[\x00-\x20]*([\\\]*)[\\x00-\x20]*@([\\\]*)[\x00-\x20]*i([\\\]*)[\x00-\x20]*m([\\\]*)[\x00-\x20]*p([\\\]*)[\x00-\x20]*o([\\\]*)[\x00-\x20]*r([\\\]*)[\x00-\x20]*t#iU', '...', $string); //@IMPORT 
    $string = preg_replace('#([a-z]*)[\x00-\x20]*e[\x00-\x20]*x[\x00-\x20]*p[\x00-\x20]*r[\x00-\x20]*e[\x00-\x20]*s[\x00-\x20]*s[\x00-\x20]*i[\x00-\x20]*o[\x00-\x20]*n#iU', '...', $string); //EXPRESSION 
    $string = preg_replace('#</*\w+:\w[^>]*>#i', "", $string); 
    $string = preg_replace('#</?t(able|r|d)(\s[^>]*)?>#i', '', $string); // strip out tables 
    $string = preg_replace('/(potspace|pot space|rateuser|marquee)/i', '...', $string); // filter some words 
    //$string = str_replace('left:0px; top: 0px;','',$string); 
    do { 
     $oldstring = $string; 
     //bgsound| 
     $string = preg_replace('#</*(applet|meta|xml|blink|link|script|iframe|frame|frameset|ilayer|layer|title|base|body|xml|AllowScriptAccess|big)[^>]*>#i', "...", $string); 
    } while ($oldstring != $string); 
    return addslashes($string); 
} 

上述工作得很好,我从未有过2年后用,但对于白名单的方式使用的任何问题,有什么同类者到stackoverflows C#方法,但在PHP中? http://refactormycode.com/codes/333-sanitize-html

回答

13

HTML Purifier是符合标准的HTML 过滤 库用PHP编写的。 HTML过滤 不仅将移除所有恶意 代码(更好地称为XSS)与 彻底的审计,安全又 宽松的白名单,这也 将确保您的文档 符合标准,只有 实现了全面 东西了解W3C的规范。

+1

使用PHP,这是真正的路要走。它的输出是惊人的和安全的。 – DGM 2009-09-04 04:01:22

+0

我以前见过这个,但我觉得它确实很笨重,不过,我会再次检查一遍,谢谢 – JasonDavis 2009-09-04 14:27:14

+0

在我需要的东西上搜索大约半小时,直到我遇到你的帖子! :-) 谢谢 – 2017-08-09 11:05:59

8

也许用DOMDocument正确分析它比较安全,用removeChild()去掉不允许的标签然后得到结果。 用正则表达式过滤东西并不总是安全的,特别是如果事情开始变得如此复杂。黑客可以找到一种方法来欺骗你的过滤器,论坛和社交网络都知道这一点。

例如,浏览器忽略<之后的空格。您的正则表达式筛选器<脚本,但如果我使用<脚本...大失败!

-1

实现这个目标非常简单 - 您只需检查任何不是来自列入白名单的标记列表中的某些标记并将其从源代码中删除即可。它可以用一个正则表达式很容易地完成。

function sanitize($html) { 
    $whitelist = array(
    'b', 'i', 'u', 'strong', 'em', 'a' 
); 

    return preg_replace("/<(^".implode("|", $whitelist).")(.*)>(.*)<\/(^".implode("|", $whitelist).")>/", "", $html); 
} 

我还没有测试过这个,那里可能有一个错误,但你得到了它的工作原理。您可能也想看看使用格式化语言(如Textile或Markdown)。

Jamie

0

您可以只使用strip_tags()函数

由于函数定义为

string strip_tags (string $str [, string $allowable_tags ]) 

你可以这样做:

$html = $_POST['content']; 
$html = strip_tags($html, '<b><a><i><u><span>'); 

不过,要注意的是使用用strip_tags ,您将无法过滤属性。例如

<a href="javascript:alert('haha caught cha!');">link</a> 
0

试试这个功能“getCleanHTML”下面,从与白名单中的标签名称元素异常的元素中提取文本内容。这段代码很干净,易于理解和调试。

<?php 

$TagWhiteList = array(
    'b', 'i', 'u', 'strong', 'em', 'a', 'img' 
); 

function getHTMLCode($Node) { 
    $Document = new DOMDocument();  
    $Document->appendChild($Document->importNode($Node, true)); 
    return $Document->saveHTML(); 
} 
function getCleanHTML($Node, $Text = "") { 
    global $TagWhiteList; 

    $TextName = $Node->tagName; 
    if ($TextName == null) 
     return $Text.$Node->textContent; 

    if (in_array($TextName, $TagWhiteList)) 
     return $Text.getHTMLCode($Node); 

    $Node = $Node->firstChild; 
    if ($Node != null) 
     $Text = getCleanHTML($Node, $Text); 

    while($Node->nextSibling != null) { 
     $Text = getCleanHTML($Node->nextSibling, $Text); 
     $Node = $Node->nextSibling; 
    } 
    return $Text; 
} 

$Doc = new DOMDocument(); 
$Doc->loadHTMLFile("Test.html"); 
echo getCleanHTML($Doc->documentElement)."\n"; 

?> 

希望这会有所帮助。

1

对于那些建议只使用strip_tags的人...请注意:strip_tags不会去掉标签属性,并且破碎的标签也会将其搞乱。

从手册页:

警告由于用strip_tags()实际上不验证HTML,局部的,或可导致去除更多的文本/数据的破碎的标签比预期的。

警告此功能不会修改 标签上的任何属性,你 允许使用allowable_tags,包括 风格和的onmouseover属性 ,一个调皮的用户可能会滥用时将显示 其他 发布文字用户。

你不能只依赖这一个解决方案。