I was running into the same issue when I had both cookie_secure
set to true and csrf_protection
set to true.
What I first noticed was the CSRF cookie wasn't being set.
Looking at the csrf_set_cookie()
function in /system/core/Security.php
, you'll see:
/**
* Set Cross Site Request Forgery Protection Cookie
*
* @return object
*/
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;
}
Though, like most, I use a load balancer for SSL termination. The individual servers don't know the traffic is over HTTPS, since the traffic is sent to each server over port 80 on the internal network. This is what the HTTP_X_FORWARDED_PROTO
is for.
I ended up overwriting the csrf_set_cookie()
in my /application/core/MY_Security.php
to fix this:
/**
* Set Cross Site Request Forgery Protection Cookie
*
* @return object
*/
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') &&
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] != 'https')
) {
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;
}