###CI 2 SESSION的詬病 相信無數人在使用CI2的Session類庫時,遇到各類的坑,各類抱怨,各類不解。在CI中國論壇能搜到大量關於Session類庫的提問,說明要想用好session類庫仍是得下一番功夫。 ####Session和cookie的區別 在某些語境中,cookie是session的一種實現方式,Ci 2的類庫設計彷佛就這麼認爲的。因而,產生了CI2中COOKIE即SESSION的說法。在安全性方面,CI 2固然也由考慮,COOKIE是通過加密過的,並且一旦修改,服務器便再也不識別。php
**CI 2的session工做原理 **redis
CI 2提供了一個元數據,咱們能夠把這個元數據看爲一個自定義的驗證機制,其包含如下內容:安全
Array ( [session_id] => 4a5a5dca22728fb0a84364eeb405b601 [ip_address] => 127.0.0.1 [user_agent] => Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; [last_activity] => 1303142623 )
其中Session id是重要的,Session id不對,直接拒絕。 驗證選項在配置文件裏有規定,(IP地址的限制)(user agent限制)(上次活動時間)等服務器
$config['sess_match_ip'] = FALSE; $config['sess_match_useragent'] = TRUE; $config['sess_time_to_update'] = 300;
特別是當設置sess_match_useragent設爲TRUE時,會遇到各類的坑: 你用flash組件上傳文件,只有登陸的用戶才能上傳文件,結果你每次判斷用戶是否登陸都會出錯,由於flash發送的http請求有可能更改了user agent; 使用ie切換不一樣的模式,好比兼容模式,也會形成user agent不一樣; user agent的長度最長是120個字符,手動設置User agent是須要截取字符到最大120個。 另外,若是出現「Cannot modify header information - headers already sent by」錯誤,基本能夠判定是你文件的編碼格式有誤,請去掉bom頭。cookie
####安全問題session
CI使用cookie來傳遞數據原本就不夠安全,並且若是數據量巨大時也會有性能問題。可是CI仍是友好地加入如下幾個安全驗證機制:tcp
加密令牌memcached
$config['encryption_key'] = 'mahuaz_'; $config['sess_encrypt_cookie'] = TRUE;
設置後,客戶端檢查cookie時就能夠看到加密後的序列化數據。性能
自動更新機制測試
CI默認每五分鐘更新一次令牌,更新發生在客戶端的一次請求中。客戶端每發送一次請求,會把cookie的信息發送到服務器,服務器根據發來的cookie判斷是否到了應該更換令牌的時間了,若是是,就會從新換一個新的令牌返回給客戶端。這就至關於門衛給你換了令牌,下次要使用新令牌進門。此時即便有壞人僞造了一個令牌也不起做用了,由於舊令牌已經做廢。這樣就至關於加了一條安全機制。可使用:
$config['sess_time_to_update'] = 300;
來設置多長時間來換一次令牌。這個時間不要設置的過短,更新頻繁也會影響性能。這裏不要和sess_expiration混淆:
$config['sess_expiration'] = 7200;
這個配置是用來指示整個cookie的過時時間的,至關於令牌徹底失效,再怎麼更換都不起做用。
###CI 3的變動 CI3的Session的重大改變就是默認使用了原生的Session,這符合Session類庫原本的意思,彷佛更加合理一些。整體來講,雖然設計理念不一樣,但爲了保證向後兼容性,類庫的使用方法與CI2.0的差異不是很大。通常的使用過程是這樣的:
截取一段CI2 SESSION的代碼:
if ($this->sess_encrypt_cookie == TRUE) { $this->CI->load->library('encrypt'); } if ($this->sess_use_database === TRUE AND $this->sess_table_name != '') { $this->CI->load->database(); } $this->now = $this->_get_time(); if ($this->sess_expiration == 0) { $this->sess_expiration = (60*60*24*365*2); } $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
截取一段CI3 SESSION的代碼:
$class = $this->_ci_load_classes($this->_driver); // Configuration ... $this->_configure($params); $class = new $class($this->_config); if ($class instanceof SessionHandlerInterface) { if (is_php('5.4')) { session_set_save_handler($class, TRUE); } else { session_set_save_handler( array($class, 'open'), array($class, 'close'), array($class, 'read'), array($class, 'write'), array($class, 'destroy'), array($class, 'gc') ); register_shutdown_function('session_write_close'); } } else { log_message('error', "Session: Driver '".$this->_driver."' doesn't implement SessionHandlerInterface. Aborting."); return; }
能夠看到CI 3已經徹底重寫了SESSION,由不一樣的驅動器用來保存SESSION(而且淘汰了COOKIE)。
###CI3 SESSION FOR REDIS 在配置文件中,CI 3的配置也徹底縮減了不少
$config['sess_driver'] = 'files'; $config['sess_cookie_name'] = 'ci_session'; $config['sess_expiration'] = 7200; $config['sess_save_path'] = NULL; $config['sess_match_ip'] = FALSE; $config['sess_time_to_update'] = 300; $config['sess_regenerate_destroy'] = FALSE;
CI 3 能夠配置驅動器類型,包括files, database, redis, memcached以及自定義,$config['sess_driver'] 來配置驅動器,默認的驅動器是files。官方推薦用files類型(在通常狀況下) 配置session save path 配置節sess_save_path會根據不一樣的驅動器,定義不一樣。 爲了適用redis,我這裏將他配置爲
tcp://127.0.0.1:6379
在上面的代碼中,有下面這兩句
$class = new $class($this->_config); if ($class instanceof SessionHandlerInterface){ ... }
確立了$_SEESION 由 redis進行存儲,加載的類是Session_redis_driver(位於sytstem/libraries/Session_redis_driver),在測試控制器中, 咱們寫一些測試代碼:
$_SESSION['test'] = 'There is test!'; var_dump($_SESSION);
會打印出
array(2) { ["__ci_last_regenerate"]=> int(1444637502) ["test"]=> string(13) "There is test" }
咱們在Session_redis_driver的read方法中寫到
var_dump($this->_key_prefix.$session_id); //redis key的值,由_key_prefix.$session_id組合構成
會打印出
string(51) "ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58"
爲了測試redis,咱們能夠在PHP中測試:
$redis = new redis(); $redis->connect('127.0.0.1',6379); var_dump($redis->get("ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58"));
會打印出
string(60) "__ci_last_regenerate|i:1444637502;test|s:13:"There is test";"
一樣,咱們在redis-cli中輸入
get ci_session:23ea4298dc5e7d6b808ca70ddb1665590e5cfb58
會打印出
__ci_last_regenerate|i:1444637502;test|s:13:"There is test
至此,CI 3 使用REDIS做爲SESSION存儲就分析完畢了