Codeigniter CSRF令牌问题

7
我制作了一个简单的注册/新闻通讯网站,但我遇到了一个奇怪的问题。有些人会收到一个错误信息,上面写着: “发生错误 请求的操作不被允许。” 我已经尝试过谷歌搜索,并发现当CSRF设置为true时,一些人会遇到同样的问题。然而,并不是每个人都会遇到这个问题,只有一小部分人。我使用form_open和form_close,并且可以看到隐藏字段(令牌)。 我正在使用Codeigniter 2.0.2的最新版本。 这是我的控制器:
    function __construct() {
    parent::__construct();
    session_start();
}

function index() {

    $this->load->model('beta_signup_model');

    $this->form_validation->set_rules('mail','e-mail','required|valid_email|xss_clean|callback__mail_check');

    // Check for errors
    if($this->form_validation->run() == FALSE) {

        // The system found a form validation error


    } else {

        // No errors found
        $_SESSION['mail_success'] = 1;
        $_SESSION['mail'] = $this->input->post('mail');

        redirect(base_url() . 'confirm');

    }

    ///// FILLS OUT INPUT FIELDS /////

    // Loads field_populator_helper
    $this->load->helper('field_populator_helper');

    // Defines input field names
    $input_names = array(
                    'mail',
    );

    // Defines default values   
    $default_values = array(
                    'Skriv inn e-posten din..',
    );

    // Auto-populates fields with blur and focus
    $data['field_populator'] = populateFields($input_names, $default_values);

    $this->load->view('frontpage_view', $data);

}

可能该功能需要 cookies 和/或 JavaScript。有些人可能出现错误是因为他们没有启用所需的功能,因此 CSRF 检查(基于令牌?)无法通过。您正在使用哪个组件进行 CSRF 防护? - hakre
我曾经也遇到过同样的问题。每当验证表单重复提交时就会发生这种情况。也许有人在这里有解决方案。 - Sukumar
有人对这个问题有解决方案吗?这很奇怪。 - Dexty
6个回答

2

为了确保没有空格或下划线,建议您在config.php中更改'sess_cookie_name'。

$config['sess_cookie_name'] = 'mycookiename';

2
我也遇到了同样的问题:在MAMP上进行全新安装CI 2.1.0,并按照用户指南中的教程操作。经过大量搜索和谷歌,我发现在“application/config.php”中,变量$config['cookie_prefix']必须始终设置为空,否则如果开启CSRF保护,就会出现此错误。 可能还涉及其他问题,例如会话库、加密或XSS保护等,但只需将“cookie_prefix”留空即可解决该问题。 希望这能帮助其他人。

1
对于使用Codeigniter 3.0的任何人,您可以执行以下操作: 更改
$config['csrf_regenerate'] = TRUE;

$config['csrf_regenerate'] = FALSE;

这将防止在每次提交时重新生成CSRF令牌。


给所有的踩贴者:http://security.stackexchange.com/questions/22903/why-refresh-csrf-token-per-form-request - qwertzman
同意,每个请求重新生成令牌,以防止在重新提交表单时失败,例如因为网络超时或其他情况... 我投赞成票。 - Angga Ari Wijaya

1

我使用自己的csrf助手,因为我发现当在配置中将选项设置为true时,它会对我的ajax调用造成混乱。

我使用*xsrf_get_token_field()*生成字段,并在我的表单验证中使用*xsrf_check_token()*作为自定义回调函数。

<

?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

if ( ! function_exists('xsrf_get_token')) {
    /**
     * Get XSRF Token
     * 
     * Returns a token that exists for one request that verifies that
     * the action was executed by the person that requested it
     *
     * @return  string
     */
    function xsrf_get_token() {
        $ci =& get_instance();
        if ($ci->session->userdata('xsrf_hash')) {
            $token = $ci->session->userdata('xsrf_hash');
        } else {
            // Generate the token
            $token = sha1(microtime().$ci->uri->uri_string());
            // Set it in the session
            $ci->session->set_userdata('xsrf_hash', $token);
        }

        //Return it
        return $token;
    }
}

if ( ! function_exists('xsrf_get_token_field')) {
    /**
     * Get XSRF Token Field
     * 
     * Returns an xhtml form element to include xsrf token.
     * You can specify the id/name attribute of the input.
     * Has a dependancy to get_xsrf_token().
     *
     * @param   string  The id/name to be used
     * @return  string
     */
    function xsrf_get_token_field($name='auth_token') {
        return '<input type="hidden" id="'.$name.'" name="'.$name.'" value="' .xsrf_get_token(). '" />';
    }
}

if ( ! function_exists('xsrf_delete_token')) {
    /**
     * Delete XSRF Token
     * 
     * Deletes the xsrf token
     *
     * @return  boolean
     */
    function xsrf_delete_token() {
        $ci =& get_instance();
        if ($ci->session->userdata('xsrf_hash')) {
            $ci->session->unset_userdata('xsrf_hash');
            return TRUE;
        } else {
            return FALSE;
        }
    }
}

if ( ! function_exists('xsrf_check_token')) {
    /**
     * Get XSRF Token Field
     * 
     * Checks that the token is still valid, returns true if so. 
     * Deletes old token after valid or fail.
     * Has a dependacy to xsrf_delete_token()
     *
     * @param   string  The challenge token
     * @return  boolean
     */
    function xsrf_check_token($challenge_token) {
        // CI
        $ci =& get_instance();
        // Get the stored token
        $token = $ci->session->userdata('xsrf_hash');
        // Delete the old token
        xsrf_delete_token();
        // Returns if the token is the right token
        return ($token == $challenge_token);
    }
}

没有理由让Ajax引起混乱 http://ericlbarnes.com/post/10728867961/codeigniter-csrf-protection-with-ajax - JonoB

1

很可能是会话问题。我曾经在CI的会话垃圾回收过程中遇到过噩梦,而且我不知道他们是否解决了所有问题。特别是如果问题难以重现并且只影响少数人,我会减少会话刷新超时时间,看看是否更容易重现。 - landons

1
  • 您需要更新核心安全文件,或者只需从当前版本的CodeIgniter CodeIgniter核心安全文件中获取csrf代码。

  • 您可以使用ajax如下: var cct = $(“input [name = csrf_test_name]”)。val(); $.post(site_url +“user / update_product”,{product_id:id,'csrf_test_name':cct})

  • Codeigniter CSRF不会在页面刷新时重新生成令牌。 它只会在发布而不是获取时重新生成。 安全测试人员发现它是一个漏洞。 如果有任何人找到了解决方法,请分享一下,这将对每个人都有帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,