有没有人知道有一个很好的功能来过滤来自表单的通用输入? Zend_Filter_input似乎需要事先了解输入的内容,我担心使用像HTML Purifier这样的东西会对性能产生很大的影响。
如下所示:http://snipplr.com/view/1848/php--sacar-xss/
非常感谢任何意见。
答案 0 :(得分:78)
简单的方法?使用strip_tags()
:
$str = strip_tags($input);
您也可以使用filter_var()
:
$str = filter_var($input, FILTER_SANITIZE_STRING);
filter_var()
的优点是你可以控制行为,例如,剥离或编码低位和高位字符。
以下是sanitizing filters的列表。
答案 1 :(得分:26)
黑客可以通过多种方式进行XSS攻击,PHP的内置功能不会对各种XSS攻击做出反应。因此,诸如strip_tags,filter_var,mysql_real_escape_string,htmlentities,htmlspecialchars等函数不会100%保护我们。你需要一个更好的机制,这就是解决方案:
function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
// Remove any attribute starting with "on" or xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
// Remove javascript: and vbscript: protocols
$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\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', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\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', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);
// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);
// Remove namespaced elements (we do not need them)
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
do
{
// Remove really unwanted tags
$old_data = $data;
$data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
}
while ($old_data !== $data);
// we are done...
return $data;
}
答案 2 :(得分:7)
最好和最安全的方法是使用HTML Purifier。请点击此链接获取与Zend Framework一起使用的一些提示。
答案 3 :(得分:3)
我有类似的问题。我需要用户使用一个很棒的WYSIWYG编辑器(Redactorjs!)将html内容提交到个人资料页面,我编写了以下函数来清理提交的html:
<?php function filterxss($str) {
//Initialize DOM:
$dom = new DOMDocument();
//Load content and add UTF8 hint:
$dom->loadHTML('<meta http-equiv="content-type" content="text/html; charset=utf-8">'.$str);
//Array holds allowed attributes and validation rules:
$check = array('src'=>'#(http://[^\s]+(?=\.(jpe?g|png|gif)))#i','href'=>'|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i');
//Loop all elements:
foreach($dom->getElementsByTagName('*') as $node){
for($i = $node->attributes->length -1; $i >= 0; $i--){
//Get the attribute:
$attribute = $node->attributes->item($i);
//Check if attribute is allowed:
if( in_array($attribute->name,array_keys($check))) {
//Validate by regex:
if(!preg_match($check[$attribute->name],$attribute->value)) {
//No match? Remove the attribute
$node->removeAttributeNode($attribute);
}
}else{
//Not allowed? Remove the attribute:
$node->removeAttributeNode($attribute);
}
}
}
var_dump($dom->saveHTML()); } ?>
$ check数组包含所有允许的属性和验证规则。也许这对你们中的一些人有用。我尚未测试,欢迎提示
答案 4 :(得分:2)
function clean($data){
$data = rawurldecode($data);
return filter_var($data, FILTER_SANITIZE_SPEC_CHARS);
}
答案 5 :(得分:1)
htmlspecialchars()
非常适合过滤以html格式显示的用户输入。
答案 6 :(得分:0)
根据www.mcafeesecure.com一般解决方案易受跨站点脚本(XSS)过滤功能可以是:
function xss_cleaner($input_str) {
$return_str = str_replace( array('<','>',"'",'"',')','('), array('<','>',''','"',')','('), $input_str );
$return_str = str_ireplace( '%3Cscript', '', $return_str );
return $return_str;
}
答案 7 :(得分:0)
尝试使用Clean XSS
xss_clean($data): "><script>alert(String.fromCharCode(74,111,104,116,111,32,82,111,98,98,105,101))</script>
答案 8 :(得分:0)
以上所有方法都不允许保留某些代码,例如<a>
,<table>
等。有一个终极解决方案http://sourceforge.net/projects/kses/
Drupal使用它
答案 9 :(得分:0)
我通过网络收集了大部分问题,并为所有问题组合了步进过滤器。
经过一些测试,它看起来很完美:
/*
* Total XSS preventer class by Full-R
*
*/
final class xCleaner {
public static function clean( string $html ): string {
return self::cleanXSS(
preg_replace(
[
'/\s?<iframe[^>]*?>.*?<\/iframe>\s?/si',
'/\s?<style[^>]*?>.*?<\/style>\s?/si',
'/\s?<script[^>]*?>.*?<\/script>\s?/si',
'#\son\w*="[^"]+"#',
],
[
'',
'',
''
],
$html
)
);
}
protected static function hexToSymbols( string $s ): string {
return html_entity_decode($s, ENT_XML1, 'UTF-8');
}
protected static function escape( string $s, string $m = 'attr' ): string {
preg_match_all('/data:\w+\/([a-zA-Z]*);base64,(?!_#_#_)([^)\'"]*)/mi', $s, $b64, PREG_OFFSET_CAPTURE);
if( count( array_filter( $b64 ) ) > 0 ) {
switch( $m ) {
case 'attr':
$xclean = self::cleanXSS(
urldecode(
base64_decode(
$b64[ 2 ][ 0 ][ 0 ]
)
)
);
break;
case 'tag':
$xclean = self::cleanTagInnerXSS(
urldecode(
base64_decode(
$b64[ 2 ][ 0 ][ 0 ]
)
)
);
break;
}
return substr_replace(
$s,
'_#_#_'. base64_encode( $xclean ),
$b64[ 2 ][ 0 ][ 1 ],
strlen( $b64[ 2 ][ 0 ][ 0 ] )
);
}
else {
return $s;
}
}
protected static function cleanXSS( string $s ): string {
// base64 injection prevention
$st = self::escape( $s, 'attr' );
return preg_replace([
// JSON unicode
'/\\\\u?{?([a-f0-9]{4,}?)}?/mi', // [1] unicode JSON clean
// Data b64 safe
'/\*\w*\*/mi', // [2] unicode simple clean
// Malware payloads
'/:?e[\s]*x[\s]*p[\s]*r[\s]*e[\s]*s[\s]*s[\s]*i[\s]*o[\s]*n[\s]*(:|;|,)?\w*/mi', // [3] (:expression) evalution
'/l[\s]*i[\s]*v[\s]*e[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t[\s]*(:|;|,)?\w*/mi', // [4] (livescript:) evalution
'/j[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t[\s]*(:|;|,)?\w*/mi', // [5] (jscript:) evalution
'/j[\s]*a[\s]*v[\s]*a[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t[\s]*(:|;|,)?\w*/mi', // [6] (javascript:) evalution
'/b[\s]*e[\s]*h[\s]*a[\s]*v[\s]*i[\s]*o[\s]*r[\s]*(:|;|,)?\w*/mi', // [7] (behavior:) evalution
'/v[\s]*b[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t[\s]*(:|;|,)?\w*/mi', // [8] (vsbscript:) evalution
'/v[\s]*b[\s]*s[\s]*(:|;|,)?\w*/mi', // [9] (vbs:) evalution
'/e[\s]*c[\s]*m[\s]*a[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t*(:|;|,)?\w*/mi', // [10] (ecmascript:) possible ES evalution
'/b[\s]*i[\s]*n[\s]*d[\s]*i[\s]*n[\s]*g*(:|;|,)?\w*/mi', // [11] (-binding) payload
'/\+\/v(8|9|\+|\/)?/mi', // [12] (UTF-7 mutation)
// Some entities
'/&{\w*}\w*/mi', // [13] html entites clenup
'/&#\d+;?/m', // [14] html entites clenup
// Script tag encoding mutation issue
'/\¼\/?\w*\¾\w*/mi', // [21] mutation KOI-8
'/\+ADw-\/?\w*\+AD4-\w*/mi', // [22] mutation old encodings
'/\/*?%00*?\//m',
// base64 escaped
'/_#_#_/mi', // [23] base64 escaped marker cleanup
],
// Replacements steps :: 23
['&#x$1;', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
str_ireplace(
['\u0', ':', '&tab;', '&newline;'],
['\0', ':', '', ''],
// U-HEX prepare step
self::hexToSymbols( $st ))
);
}
}
您也可以添加 Tidy 标记更正以使 HTML 有效。
答案 10 :(得分:-1)
我找到了一个解决我的问题的解决方案与德国变音符号的帖子。为了提供完全清理(查杀)帖子,我对输入数据进行编码:
*$data = utf8_encode($data);
... function ...*
最后我解码输出以获得正确的符号:
*$data = utf8_decode($data);*
现在帖子通过过滤功能,我得到了正确的结果......