温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

CI的CSRF的改造

发布时间:2020-09-13 12:33:51 来源:网络 阅读:466 作者:dfwasds 栏目:web开发

CI的CSRF是有缺陷的。

只要同时开俩个不同的涉及csrf的页面,

http://host/csrf1

http://host/csrf2

就会发现页面直接互相影响(问题1)。


 即使同一页面也涉及这样的问题。

http://host/csrf1

http://host/csrf1

也会发现这样的问题(问题2)。


先解决简单问题2

只需要将配置 csrf_regenerate 设置为 false; 即是cookie过期或者被清掉。

$config['csrf_regenerate'] = FALSE;



解决复杂问题1:

一. 将system/core/Input 中的 验证代码过滤。 

// CSRF Protection check
if ($this->_enable_csrf === TRUE && ! is_cli())
{
   //$this->security->csrf_verify();
}


二. 改造Security类

class CI_Security {


	/**
	 * Class constructor
	 *
	 * @return	void
	 */
	public function __construct()
	{
		$this->charset = strtoupper(config_item('charset'));

		log_message('info', 'Security Class Initialized');
	}

	public function start_csrf($class, $function)
	{
		// Is CSRF protection enabled?
		if (config_item('csrf_protection'))
		{

			if(!$class || !$function){
				return ;
			}
			$this->_csrf_cookie_name = md5($class.'_'.$function);
			// CSRF config
			foreach (array(
						 'csrf_expire',
						 'csrf_token_name',
						 //'csrf_cookie_name',
					 ) as $key)
			{
				if (NULL !== ($val = config_item($key)))
				{
					$this->{'_'.$key} = $val;
				}
			}

			// Append application specific cookie prefix
			if ($cookie_prefix = config_item('cookie_prefix'))
			{
				//$this->_csrf_cookie_name = $cookie_prefix.$this->_csrf_cookie_name;
			}

			// Set the CSRF hash
			$this->_csrf_set_hash();
			$this->csrf_set_cookie();
		}
	}

	// --------------------------------------------------------------------

	/**
	 * CSRF Verify
	 *
	 * @return	CI_Security
	 */
	public function csrf_verify($class, $function)
	{
		if (!config_item('csrf_protection')){
			return ;
		}
		if(!$class || !$function){
			return ;
		}
		$this->_csrf_cookie_name = md5($class.'_'.$function);

		// CSRF config
		foreach (array(
					 'csrf_expire',
					 'csrf_token_name',
					 //'csrf_cookie_name',
				 ) as $key)
		{
			if (NULL !== ($val = config_item($key)))
			{
				$this->{'_'.$key} = $val;
			}
		}
		// If it's not a POST request we will set the CSRF cookie
		if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
		{
			//return $this->csrf_set_cookie();
			$this->csrf_show_error();
		}

		// Check if URI has been whitelisted from CSRF checks
		if ($exclude_uris = config_item('csrf_exclude_uris'))
		{
			$uri = load_class('URI', 'core');
			foreach ($exclude_uris as $excluded)
			{
				if (preg_match('#^'.$excluded.'$#i'.(UTF8_ENABLED ? 'u' : ''), $uri->uri_string()))
				{
					return $this;
				}
			}
		}

		// Check CSRF token validity, but don't error on mismatch just yet - we'll want to regenerate
		$valid = isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])
			&& hash_equals($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name]);

		// We kill this since we're done and we don't want to pollute the _POST array
		unset($_POST[$this->_csrf_token_name]);

		// Regenerate on every submission?
		if (config_item('csrf_regenerate'))
		{
			// Nothing should last forever
			unset($_COOKIE[$this->_csrf_cookie_name]);
			$this->_csrf_hash = NULL;
		}

		$this->_csrf_set_hash();
		$this->csrf_set_cookie();

		if ($valid !== TRUE)
		{
			$this->csrf_show_error();
		}

		log_message('info', 'CSRF token verified');
		return $this;
	}

	// --------------------------------------------------------------------

	/**
	 * CSRF Set Cookie
	 *
	 * @codeCoverageIgnore
	 * @return	CI_Security
	 */
	public function csrf_set_cookie()
	{
		if (!config_item('csrf_protection')){
			return ;
		}
		$expire = time() + $this->_csrf_expire;
		$secure_cookie = (bool) config_item('cookie_secure');

		if ($secure_cookie && ! is_https())
		{
			return FALSE;
		}

		setcookie(
			$this->_csrf_cookie_name,
			$this->_csrf_hash,
			$expire,
			config_item('cookie_path'),
			config_item('cookie_domain'),
			$secure_cookie,
			config_item('cookie_httponly')
		);
		log_message('info', 'CSRF cookie sent');

		return $this;
	}

	// --------------------------------------------------------------------

	/**
	 * Set CSRF Hash and Cookie
	 *
	 * @return	string
	 */
	protected function _csrf_set_hash()
	{
		if (!config_item('csrf_protection')){
			return ;
		}
		if ($this->_csrf_hash === NULL)
		{
			// If the cookie exists we will use its value.
			// We don't necessarily want to regenerate it with
			// each page load since a page could contain embedded
			// sub-pages causing this feature to fail
			if (isset($_COOKIE[$this->_csrf_cookie_name]) && is_string($_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];
			}

			$rand = $this->get_random_bytes(16);
			$this->_csrf_hash = ($rand === FALSE)
				? md5(uniqid(mt_rand(), TRUE))
				: bin2hex($rand);
		}

		return $this->_csrf_hash;
	}

}


三.使用实例

controller

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller {

   public function csrf_test1()
   {
      if($_POST){
         $this->security->csrf_verify(__CLASS__, __FUNCTION__);
         var_dump($_POST);
         exit;
      }

      $this->security->start_csrf(__CLASS__, __FUNCTION__);
      $csrf = array(
         'name' => $this->security->get_csrf_token_name(),
         'hash' => $this->security->get_csrf_hash()
      );
      $data['csrf'] = $csrf;
      $this->load->view('csrf1', $data);
   }
}

view

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Welcome to CodeIgniter</title>

    <style type="text/css">

        ::selection { background-color: #E13300; color: white; }
        ::-moz-selection { background-color: #E13300; color: white; }

        body {
            background-color: #fff;
            margin: 40px;
            font: 13px/20px normal Helvetica, Arial, sans-serif;
            color: #4F5155;
        }

        a {
            color: #003399;
            background-color: transparent;
            font-weight: normal;
        }

        h2 {
            color: #444;
            background-color: transparent;
            border-bottom: 1px solid #D0D0D0;
            font-size: 19px;
            font-weight: normal;
            margin: 0 0 14px 0;
            padding: 14px 15px 10px 15px;
        }

        code {
            font-family: Consolas, Monaco, Courier New, Courier, monospace;
            font-size: 12px;
            background-color: #f9f9f9;
            border: 1px solid #D0D0D0;
            color: #002166;
            display: block;
            margin: 14px 0 14px 0;
            padding: 12px 10px 12px 10px;
        }

        #body {
            margin: 0 15px 0 15px;
        }

        p.footer {
            text-align: right;
            font-size: 11px;
            border-top: 1px solid #D0D0D0;
            line-height: 32px;
            padding: 0 10px 0 10px;
            margin: 20px 0 0 0;
        }

        #container {
            margin: 10px;
            border: 1px solid #D0D0D0;
            box-shadow: 0 0 8px #D0D0D0;
        }
    </style>
</head>
<body>

<div id="container">
    <h2>Welcome to CodeIgniter!</h2>

    <div id="body">
        <form method="post" action="/welcome/csrf_test1">
            <table>
                <tbody>
                <tr>
                    <td>用户名:</td>
                    <td colspan="3"><input type="text" id="user_name" class="text" name="username"></td>
                </tr>
                <tr>
                    <td>密&nbsp;&nbsp;码:</td>
                    <td class="width260"><input type="password" class="text" name="password"></td>
                    <td colspan="2">&nbsp;</td>
                </tr>
                <tr>
                    <th colspan="4"> <input class="btnenter" type="submit">
                        <input type="hidden" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" />
                </tr>
                </tbody>
            </table>
        </form>
    </div>

</div>

</body>
</html>


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI