CI框架安全类Security.php源码分析

前端之家收集整理的这篇文章主要介绍了CI框架安全类Security.php源码分析前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

CI安全类提供了全局防御CSRF攻击和XSS攻击策略,只需要在配置文件开启即可:

代码如下:

并提供了实用方法

代码如下:
security->xss_clean($data);//第二个参数为TRUE,验证图片安全 $this->security->sanitize_filename()//过滤文件

CI也提供了安全函数

xss_clean()//xss过滤 sanitize_filename()//净化文件名 do_hash()//md5或sha加密 strip_image_tags() //删除图片标签的不必要字符 encode_PHP_tags()//把PHP脚本标签强制转成实体对象

代码如下:
'[removed]', 'document.write'=> '[removed]', '.parentNode'=> '[removed]', '.innerHTML'=> '[removed]', 'window.location'=> '[removed]', '-moz-binding'=> '[removed]', ''=> '-->', ' ''=> '' ); //不允许出现的正则表达式数组 protected $_never_allowed_regex = array( 'javascript\s*:', 'expression\s*(\(|&\#40;)',// CSS and IE 'vbscript\s*:',// IE,surprise! 'Redirect\s+302', "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?" ); //构造函数 public function __construct() { // CSRF保护是否开启 if (config_item('csrf_protection') === TRUE) { // CSRF配置 foreach (array('csrf_expire','csrf_token_name','csrf_cookie_name') as $key) { if (FALSE !== ($val = config_item($key))) { $this->{'_'.$key} = $val; } } // _csrf_cookie_name加上cookie前缀 if (config_item('cookie_prefix')) { $this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name; } // 设置csrf的hash值 $this->_csrf_set_hash(); } log_message('debug',"Security Class Initialized"); } // -------------------------------------------------------------------- /** * Verify Cross Site Request Forgery Protection * * @returnobject */ public function csrf_verify() { // 如果不是post请求,则设置csrf的cookie值 if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') { return $this->csrf_set_cookie(); } // Do the tokens exist in both the _POST and _COOKIE arrays? if ( ! isset($_POST[$this->_csrf_token_name],$_COOKIE[$this->_csrf_cookie_name])) { $this->csrf_show_error(); } // token匹配吗 if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name]) { $this->csrf_show_error(); } // We kill this since we're done and we don't want to // polute the _POST array unset($_POST[$this->_csrf_token_name]); // Nothing should last forever unset($_COOKIE[$this->_csrf_cookie_name]); $this->_csrf_set_hash(); $this->csrf_set_cookie(); log_message('debug','CSRF token verified'); return $this; } // -------------------------------------------------------------------- /** * 设置csrf的cookie值 */ public function csrf_set_cookie() { $expire = time() + $this->_csrf_expire; $secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0; if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off')) { return FALSE; } setcookie($this->_csrf_cookie_name,$this->_csrf_hash,$expire,config_item('cookie_path'),config_item('cookie_domain'),$secure_cookie); log_message('debug',"CRSF cookie Set"); return $this; } //csrf保存 public function csrf_show_error() { show_error('The action you have requested is not allowed.'); } //获取csrf的hash值 public function get_csrf_hash() { return $this->_csrf_hash; } //获取csrf的token值 public function get_csrf_token_name() { return $this->_csrf_token_name; } /** * XSS 过滤 */ public function xss_clean($str,$is_image = FALSE) { //是否是数组 if (is_array($str)) { while (list($key) = each($str)) { $str[$key] = $this->xss_clean($str[$key]); } return $str; } //去掉可见字符串 $str = remove_invisible_characters($str); // 验证实体url $str = $this->_validate_entities($str); /* * URL 解码 * * Just in case stuff like this is submitted: * * Google> * * Note: Use rawurldecode() so it does not remove plus signs * */ $str = rawurldecode($str); /* * Convert character entities to ASCII * * This permits our tests below to work reliably. * We only convert entities that are within tags since * these are the ones that will pose security problems. * */ $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si",array($this,'_convert_attribute'),$str); $str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si",'_decode_entity'),$str); /* * Remove Invisible Characters Again! */ $str = remove_invisible_characters($str); /* * Convert all tabs to spaces * * This prevents strings like this: javascript * NOTE: we deal with spaces between characters later. * NOTE: preg_replace was found to be amazingly slow here on * large blocks of data,so we use str_replace. */ if (strpos($str,"\t") !== FALSE) { $str = str_replace("\t",' ',$str); } /* * Capture converted string for later comparison */ $converted_string = $str; // Remove Strings that are never allowed $str = $this->_do_never_allowed($str); /* * Makes PHP tags safe * * Note: XML tags are inadvertently replaced too: * * PHP short opening and // closing tags every so often so we skip those and only // do the long opening tags. $str = preg_replace('/<\?(PHP)/i',"'),array(''),$str); } /* * Compact any exploded words * * This corrects words like: j a v a s c r i p t * These words are compacted back to their correct state. */ $words = array( 'javascript','expression','vbscript','script','base64', 'applet','alert','document','write','cookie','window' ); foreach ($words as $word) { $temp = ''; for ($i = 0,$wordlen = strlen($word); $i < $wordlen; $i++) { $temp .= substr($word,$i,1)."\s*"; } // We only want to do this when it is followed by a non-word character // That way valid stuff like "dealer to" does not become "dealerto" $str = preg_replace_callback('#('.substr($temp,-3).')(\W)#is','_compact_exploded_words'),$str); } /* * Remove disallowed Javascript in links or img tags * We used to do some version comparisons and use of stripos for PHP5, * but it is dog slow compared to these simplified non-capturing * preg_match(),especially if the pattern exists in the string */ do { $original = $str; if (preg_match("/]*?)(>|$)#si",'_js_link_removal'),$str); } if (preg_match("/]*?)(\s?/?>|$)#si",'_js_img_removal'),$str); } if (preg_match("/script/i",$str) OR preg_match("/xss/i",$str)) { $str = preg_replace("#<(/*)(script|xss)(.*?)\>#si",'[removed]',$str); } } while($original != $str); unset($original); // Remove evil attributes such as style,onclick and xmlns $str = $this->_remove_evil_attributes($str,$is_image); /* * Sanitize naughty HTML elements * * If a tag containing any of the words in the list * below is found,the tag gets converted to entities. * * So this: * Becomes: */ $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss'; $str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is','_sanitize_naughty_html'),$str); /* * Sanitize naughty scripting elements * * Similar to above,only instead of looking for * tags it looks for PHP and JavaScript commands * that are disallowed. Rather than removing the * code,it simply converts the parenthesis to entities * rendering the code un-executable. * * For example:eval('some code') * Becomes:eval('some code') */ $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si',")",$str); // Final clean up // This adds a bit of extra precaution in case // something got through the above filters $str = $this->_do_never_allowed($str); /* * Images are Handled in a Special Way * - Essentially,we want to know that after all of the character * conversion is done whether any unwanted,likely XSS,code was found. * If not,we return TRUE,as the image is clean. * However,if the string post-conversion does not matched the * string post-removal of XSS,then it fails,as there was unwanted XSS * code found and removed/changed during processing. */ if ($is_image === TRUE) { return ($str == $converted_string) ? TRUE: FALSE; } log_message('debug',"XSS Filtering completed"); return $str; } // -------------------------------------------------------------------- //保护url的随机hash值 public function xss_hash() { if ($this->_xss_hash == '') { mt_srand(); $this->_xss_hash = md5(time() + mt_rand(0,1999999999)); } return $this->_xss_hash; } // -------------------------------------------------------------------- /** * html实体转码 */ public function entity_decode($str,$charset='UTF-8') { if (stristr($str,'&') === FALSE) { return $str; } $str = html_entity_decode($str,ENT_COMPAT,$charset); $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei','chr(hexdec(",$str); return preg_replace('~&#([0-9]{2,4})~e','chr(,$str); } // -------------------------------------------------------------------- //过滤文件名,保证文件名安全 public function sanitize_filename($str,$relative_path = FALSE) { $bad = array( "../", "", "<", ">", "'", '"', '&', '$', '#', '{', '}', '[', ']', '=', ';', '?', "%20", "%22", "%3c",// < "%253c",// < "%3e",// > "%0e",// > "%28",// ( "%29",// ) "%2528",// ( "%26",// & "%24",// $ "%3f",// ? "%3b",// ; "%3d"// = ); if ( ! $relative_path) { $bad[] = './'; $bad[] = '/'; } $str = remove_invisible_characters($str,FALSE); return stripslashes(str_replace($bad,'',$str)); } //压缩单词如j a v a s c r i p t成javascript protected function _compact_exploded_words($matches) { return preg_replace('/\s+/s',$matches[1]).$matches[2]; } // -------------------------------------------------------------------- /* * 去掉一些危害的html属性 */ protected function _remove_evil_attributes($str,$is_image) { // All javascript event handlers (e.g. onload,onclick,onmouSEOver),style,and xmlns $evil_attributes = array('on\w*','style','xmlns','formaction'); if ($is_image === TRUE) { /* * Adobe Photoshop puts XML Metadata into JFIF images, * including namespacing,so we have to allow this for images. */ unset($evil_attributes[array_search('xmlns',$evil_attributes)]); } do { $count = 0; $attribs = array(); // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes) preg_match_all('/('.implode('|',$evil_attributes).')\s*=\s*(\042|\047)([^\\2]*?)(,$str,$matches,PREG_SET_ORDER); foreach ($matches as $attr) { $attribs[] = preg_quote($attr[0],'/'); } // find occurrences of illegal attribute strings without quotes preg_match_all('/('.implode('|',$evil_attributes).')\s*=\s*([^\s>]*)/is','/'); } // replace illegal attribute strings that are inside an html tag if (count($attribs) > 0) { $str = preg_replace('/(<]+?)([^A-Za-z<>\-])(.*?)('.implode('|',$attribs).')(.*?)([\s><]?)([><]*)/i','$1$2 $4$6$7$8',-1,$count); } } while ($count); return $str; } // -------------------------------------------------------------------- /** * 净化html,补齐未关闭的标签 */ protected function _sanitize_naughty_html($matches) { // encode opening brace $str = '<'.$matches[1].$matches[2].$matches[3]; // encode captured opening or closing brace to prevent recursive vectors $str .= str_replace(array('>','<'),array('>', $matches[4]); return $str; } // -------------------------------------------------------------------- /** * 过滤超链接中js */ protected function _js_link_removal($match) { return str_replace( $match[1], preg_replace( '#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<','>'),$match[1])) ), $match[0] ); } // -------------------------------------------------------------------- /** * 过滤图片链接中的js */ protected function _js_img_removal($match) { return str_replace( $match[1], preg_replace( '#src=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|','<','\\'),'\\\\'),$match[0]); } // -------------------------------------------------------------------- //过滤html标签属性 protected function _filter_attributes($str) { $out = ''; if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is',$matches)) { foreach ($matches[0] as $match) { $out .= preg_replace("#/\*.*?\*/#s",$match); } } return $out; } // -------------------------------------------------------------------- //html实体转码 protected function _decode_entity($match) { return $this->entity_decode($match[0],strtoupper(config_item('charset'))); } // -------------------------------------------------------------------- /** * 验证url实体 */ protected function _validate_entities($str) { /* * Protect GET variables in URLs */ // 901119URL5918AMP18930PROTECT8198 $str = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i',$this->xss_hash()."",$str); /* * Validate standard character entities * * Add a semicolon if missing. We do this to enable * the conversion of entities to ASCII later. * */ $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i',"",$str); /* * Validate UTF16 two byte encoding (x00) * * Just as above,adds a semicolon if missing. * */ $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"); /* * Un-Protect GET variables in URLs */ $str = str_replace($this->xss_hash(),'&',$str); return $str; } // ---------------------------------------------------------------------- //过滤不允许出现的字符串 protected function _do_never_allowed($str) { $str = str_replace(array_keys($this->_never_allowed_str),$this->_never_allowed_str,$str); foreach ($this->_never_allowed_regex as $regex) { $str = preg_replace('#'.$regex.'#is',$str); } return $str; } // -------------------------------------------------------------------- //设置csrf的hash值 protected function _csrf_set_hash() { if ($this->_csrf_hash == '') { // 如果_csrf_cookie_name存在,直接作为csrf hash值 if (isset($_COOKIE[$this->_csrf_cookie_name]) && preg_match('#^[0-9a-f]{32}$#iS',$_COOKIE[$this->_csrf_cookie_name]) === 1) { return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name]; } //否则随机一个md5字符串 return $this->_csrf_hash = md5(uniqid(rand(),TRUE)); } return $this->_csrf_hash; } }

猜你在找的PHP相关文章