用户
 找回密码
 入住 CI 中国社区
搜索
查看: 4450|回复: 3
收起左侧

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

[复制链接]
发表于 2014-5-19 16:45:06 | 显示全部楼层 |阅读模式
本帖最后由 ^淡如清风 于 2014-5-19 17:06 编辑

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

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


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

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

于是查看了下 form_open() 的源码
PHP复制代码
/**
 * 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;
        }
}
复制代码

发现,生成表单隐藏域重点是这几行
PHP复制代码
// 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复制代码
<?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 } ?>
复制代码

或是在控制器中把隐藏域先生成,然后在模板中直接输出
控制器:
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复制代码
<?php echo  $token; ?>
复制代码

注意:只能应用于post请求哦

发表于 2014-5-20 08:29:59 | 显示全部楼层
多谢楼主分享
发表于 2015-1-13 11:10:35 | 显示全部楼层
原来是这样!谢谢楼主
发表于 2015-9-11 09:41:24 | 显示全部楼层
如果每次$this->security->get_csrf_hash() 提交表单生成代码是一样,这是错在哪里呢?

本版积分规则