^淡如清风 发表于 2014-5-19 16:45:06

利用CI自带的security安全类实现防止跨站请求-表单增加隐藏域

本帖最后由 ^淡如清风 于 2014-5-19 17:06 编辑

首先我们看文档:http://codeigniter.org.cn/user_guide/libraries/security.html
最后几行讲解到:
跨站请求伪造(Cross-site request forgery,CSRF)

打开你的 application/config/config.php 文件,进行如下设置,即可启用 csrf 保护:
$config['csrf_protection'] = TRUE;

如果你使用 表单辅助函数, form_open() 函数将会自动地在你的表单中插入一个隐藏的csrf字段.

这是文档所介绍的方法:
必须使用 form_open() 来生成表单隐藏域,来实现防止跨站请求。

于是查看了下 form_open() 的源码
/**
* Form Declaration
*
* Creates the opening portion of the form.
*
* @access      public
* @param      string      the URI segments of the form destination
* @param      array      a key/value pair of attributes
* @param      array      a key/value pair hidden data
* @return      string
*/
if ( ! function_exists('form_open'))
{
      function form_open($action = '', $attributes = '', $hidden = array())
      {
                $CI =& get_instance();

                if ($attributes == '')
                {
                        $attributes = 'method="post"';
                }

                // If an action is not a full URL then turn it into one
                if ($action && strpos($action, '://') === FALSE)
                {
                        $action = $CI->config->site_url($action);
                }

                // If no action is provided then set to the current url
                $action OR $action = $CI->config->site_url($CI->uri->uri_string());

                $form = '<form action="'.$action.'"';

                $form .= _attributes_to_string($attributes, TRUE);

                $form .= '>';

                // Add CSRF field if enabled, but leave it out for GET requests and requests to external websites      
                if ($CI->config->item('csrf_protection') === TRUE AND ! (strpos($action, $CI->config->base_url()) === FALSE OR strpos($form, 'method="get"')))      
                {
                        $hidden[$CI->security->get_csrf_token_name()] = $CI->security->get_csrf_hash();
                }

                if (is_array($hidden) AND count($hidden) > 0)
                {
                        $form .= sprintf("<div style=\"display:none\">%s</div>", form_hidden($hidden));
                }

                return $form;
      }
}
发现,生成表单隐藏域重点是这几行
// Add CSRF field if enabled, but leave it out for GET requests and requests to external websites      
if ($CI->config->item('csrf_protection') === TRUE AND ! (strpos($action, $CI->config->base_url()) === FALSE OR strpos($form, 'method="get"')))      
{
    $hidden[$CI->security->get_csrf_token_name()] = $CI->security->get_csrf_hash();
}
于是不难发现,我们可以直接在模板中使用,方法如下
<?php if ($this->config->item('csrf_protection') === TRUE) { ?>
    <input type="hidden" name="<?php echo $this->security->get_csrf_token_name(); ?>" value="<?php echo $this->security->get_csrf_hash(); ?>" />
<?php } ?>
或是在控制器中把隐藏域先生成,然后在模板中直接输出
控制器:
$data['token'] = '';
if ($this->config->item('csrf_protection') === TRUE) {
      $data['token'] = '<input type="hidden" name="' . $this->security->get_csrf_token_name() . '" value="' . $this->security->get_csrf_hash() . '" />';
}
$this->load->view('reg_index', $data);
模板直接输出变量即可:
<?php echo$token; ?>
注意:只能应用于post请求哦

一叶扁舟 发表于 2014-5-20 08:29:59

:lol 多谢楼主分享

shaoyikai 发表于 2015-1-13 11:10:35

原来是这样!谢谢楼主

wish751 发表于 2015-9-11 09:41:24

如果每次$this->security->get_csrf_hash() 提交表单生成代码是一样,这是错在哪里呢?
页: [1]
查看完整版本: 利用CI自带的security安全类实现防止跨站请求-表单增加隐藏域