Home php教程 php手册 CI框架安全类Security.php源码分析

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

Jun 06, 2016 pm 08:18 PM
ci framework

之前我们分析了CI框架的session类session.php,本文我们继续分析CI框架的安全类security.php文件,方便我们更详细的了解CI框架,从而更熟练的应用CI框架

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

复制代码 代码如下:


$config['csrf_protection'] = TRUE;
$config['global_xss_filtering'] = TRUE;

并提供了实用方法:

复制代码 代码如下:


$this->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脚本标签强制转成实体对象

复制代码 代码如下:


/**
 * 安全类
 */
class CI_Security {
 //url的随机hash值
 protected $_xss_hash   = '';
 //防csrf攻击的cookie标记的哈希值 
 protected $_csrf_hash   = '';
 //防csrf cookie过期时间
 protected $_csrf_expire   = 7200;
 //防csrf的cookie名称
 protected $_csrf_token_name  = 'ci_csrf_token';
 //防csrf的token名称
 protected $_csrf_cookie_name = 'ci_csrf_token';
 //不允许出现的字符串数组
 protected $_never_allowed_str = array(
  'document.cookie' => '[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
  *
  * @return object
  */
 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("/|   /*
   * Remove Invisible Characters Again!
   */
  $str = remove_invisible_characters($str);
  /*
   * Convert all tabs to spaces
   *
   * This prevents strings like this: ja vascript
   * 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:
   *
   *    *
   * But it doesn't seem to pose a problem.
   */
  if ($is_image === TRUE)
  {
   // Images have a tendency to have the PHP short opening and
   // closing tags every so often so we skip those and only
   // do the long opening tags.
   $str = preg_replace('/   }
  else
  {
   $str = str_replace(array(''),  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    {
    $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, 0, -3).')(\W)#is', array($this, '_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("/    {
    $str = preg_replace_callback("#]*?)(>|$)#si", array($this, '_js_link_removal'), $str);
   }
   if (preg_match("/CI框架安全类Security.php源码分析    {
    $str = preg_replace_callback("#CI框架安全类Security.php源码分析]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str);
   }
   if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str))
   {
    $str = preg_replace("##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('#   /*
   * 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', "\\1\\2(\\3)", $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('~(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
  return preg_replace('~([0-9]{2,4})~e', 'chr(\\1)', $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]*?)(\\2)/is', $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', $str, $matches, PREG_SET_ORDER);
   foreach ($matches as $attr)
   {
    $attribs[] = preg_quote($attr[0], '/');
   }
   // replace illegal attribute strings that are inside an html tag
   if (count($attribs) > 0)
   {
    $str = preg_replace('/(\-])(.*?)('.implode('|', $attribs).')(.*?)([\s>    }
  } while ($count);
  return $str;
 }
 // --------------------------------------------------------------------
 /**
  * 净化html,补齐未关闭的标签
  */
 protected function _sanitize_naughty_html($matches)
 {
  // encode opening brace
  $str = '   // encode captured opening or closing brace to prevent recursive vectors
  $str .= str_replace(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|<script></script>     '',
    $this->_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|<script></script>     '',
    $this->_filter_attributes(str_replace(array(''), '', $match[1]))
   ),
   $match[0]
  );
 }
 // --------------------------------------------------------------------
 /**
  * 转换属性,,将一些字符转换成实体
  */
 protected function _convert_attribute($match)
 {
  return str_replace(array('>', '', '  }
 // --------------------------------------------------------------------
 //过滤html标签属性
 protected function _filter_attributes($str)
 {
  $out = '';
  if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $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()."\\1=\\2", $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', "\\1;\\2", $str);
  /*
   * Validate UTF16 two byte encoding (x00)
   *
   * Just as above, adds a semicolon if missing.
   *
   */
  $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str);
  /*
   * 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', '[removed]', $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;
 }
}

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to use CI framework in php? How to use CI framework in php? Jun 01, 2023 am 08:48 AM

With the development of network technology, PHP has become one of the important tools for Web development. One of the popular PHP frameworks - CodeIgniter (hereinafter referred to as CI) has also received more and more attention and use. Today, we will take a look at how to use the CI framework. 1. Install the CI framework First, we need to download the CI framework and install it. Download the latest version of the CI framework compressed package from CI's official website (https://codeigniter.com/). After the download is complete, unzip

How to use CI framework in PHP How to use CI framework in PHP Jun 27, 2023 pm 04:51 PM

PHP is a popular programming language that is widely used in web development. The CI (CodeIgniter) framework is one of the most popular frameworks in PHP. It provides a complete set of ready-made tools and function libraries, as well as some popular design patterns, allowing developers to develop Web applications more efficiently. This article will introduce the basic steps and methods of developing PHP applications using the CI framework. Understand the basic concepts and structures of the CI framework. Before using the CI framework, we need to understand some basic concepts and structures. Down

How to use CI4 framework in php? How to use CI4 framework in php? Jun 01, 2023 pm 02:40 PM

PHP is a widely used server-side scripting language, and CodeIgniter4 (CI4) is a popular PHP framework that provides a fast and excellent way to build web applications. In this article, we will get you started using the CI4 framework to develop outstanding web applications by walking you through how to use it. 1. Download and install CI4 First, you need to download it from the official website (https://codeigniter.com/downloa

A guide to CI frameworks in PHP A guide to CI frameworks in PHP May 22, 2023 pm 07:10 PM

With the development of the Internet and its continuous integration into people's lives, the development of network applications has become more and more important. As a well-known programming language, PHP has become one of the preferred languages ​​for developing Internet applications. Developers can use numerous PHP frameworks to simplify the development process, one of the most popular is the CodeIgniter (CI) framework. CI is a powerful PHP web application framework. It has the characteristics of lightweight, easy to use, optimized performance, etc., allowing developers to quickly build

How to introduce css into ci framework How to introduce css into ci framework Dec 26, 2023 pm 05:20 PM

The steps to introduce CSS styles in the CI framework are as follows: 1. Prepare CSS files; 2. Store the CSS files in the appropriate location of the CI framework project; 3. In the pages that need to use CSS styles, introduce CSS through the HTML <link> tag File; 4. Use the CSS class or ID name in the HTML element to apply the corresponding style.

Steps to introduce CSS styles to web pages using CI framework Steps to introduce CSS styles to web pages using CI framework Jan 16, 2024 am 09:20 AM

The steps for introducing CSS styles in the CI framework require specific code examples. The CI (CodeIgniter) framework is a popular PHP development framework that is widely used to build efficient web applications. When developing web applications, a beautiful user interface is an important consideration. Using CSS styles can optimize and personalize the web application interface, giving users a better experience. In a CI framework, introducing CSS styles usually requires the following steps, accompanied by specific code examples. step 1:

Detailed explanation of the steps to reference CSS styles in the CI framework Detailed explanation of the steps to reference CSS styles in the CI framework Jan 16, 2024 am 09:28 AM

Tutorial: Detailed steps for introducing CSS styles in the CI framework, specific code examples are required Introduction: Style is a crucial part of developing web applications. Use CSS (Cascading Style Sheets) to beautify web pages and provide a better user experience. When developing using the CodeIgniter (CI) framework, how to correctly introduce CSS styles is particularly important. This article will introduce the detailed steps of introducing CSS styles in the CI framework and provide you with specific code examples. Step 1: Create CSS File First,

How to use CI6 framework in php? How to use CI6 framework in php? Jun 01, 2023 pm 11:10 PM

PHP is a very popular web development language, and CodeIgniter (CI) is a very popular PHP framework. CodeIgniter provides many useful functions and features, bringing great convenience to developers. In this article, we will explore how to use the CI6 framework. Installing CI6 Before you can start using CI6, you must first complete the installation process. You need to first download the CI6 compressed package from the CodeIgniter official website. Then, unzip this file and place it in

See all articles