(とてもくだらない記事なので暇な人だけよむことをオススメします)
簡単なAuth認証を自作しました。
それで、セッションのタイムアウトの時間を設定するため、CakePHPのセッションを設定してみると、不可解な現象が発生した。
環境とファイル
用意したファイル
// 〜 省略 〜 Configure::write('Session', array( 'defaults' => 'cake', 'timeout' => 1 )); // 〜 省略 〜
~/cakephp/app/Controller/AppController.php
<?php // 〜 省略 〜 class AppController extends Controller { public $components = array('Session'); // 〜 省略 〜
~/cakephp/app/Controller/IndexesController.php
<?php // 〜 省略 〜 // ログインした後にセッションを保存 $this->Session->write('SitesAuth.passwd', array('passwd' => $passWd)); // 〜 省略 〜
環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.10.3 BuildVersion: 14D136 # CakePHPは2.5.8です $ cat ~/cakephp/lib/Cake/VERSION.txt 2.5.8
現象
セッションファイルを削除しても、ログインしたままになっている!!!
無理矢理ですが、session destroy してみる
IndexesController.php
<?php // 〜 省略 〜 $this->Session->destroy(); // 〜 省略 〜
削除されない!!!! うわぁああああああ▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂
無理やり削除!
rm -rf ~/cakephp/app/tmp/sessions/sess_b4s9538ca529tiklxxxxxxxx # 一旦ブラウザへアクセス・・・・!!? アクセスできた!?? ls ~/cakephp/app/tmp/sessions/sess_b4s9538ca529tiklxxxxxxxx sess_b4s9538ca529tiklxxxxxxxx
削除したのに復活した!!! うわぁああああああ▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂
そうか!ブラウザでクッキーみたいに保存されているんだな!(やけくそ)
画像のように、ChromeでDeveloper Tool 利用してクッキーをクリアしてみる。
あれ? ログインページに遷移しないぞ。。。クリアし続けても普通にセッションが続く。
セッションファイルを確認してみる。
$ ls -l ~/cakephp/app/tmp/sessions/ total 48 -rwxrwxrwx 1 user staff 0 4 24 16:50 empty -rw------- 1 _www staff 149 5 1 00:48 sess_36mdlcdhcboro1dbdn2cdq06k2 -rw------- 1 _www staff 149 5 1 00:47 sess_b4s9538ca529tiklpccvavapp3 -rw------- 1 _www staff 220 5 1 00:47 sess_iirio8mcn7manerr9c5ecrhki3 -rw------- 1 _www staff 149 5 1 00:48 sess_m59nr1r09csc39f2p735cp7r02 -rw------- 1 _www staff 152 5 1 00:48 sess_n74a94745a73nj5m1gs2pcnv76 -rw------- 1 _www staff 209 5 1 00:48 sess_s45amc958s61uroj7lu3dbdr63
増えてる!!!!! うわぁああああああ▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂
\(^o^)/オワタ
よくわからなくなったので、ちゃんと調べることにしました。(今日は残業や)
そもそもセッション(Session)とは?
ここで学びなおしました。(ちょくちょくお世話になっておりますm(_ _ )m)
一応基礎は知っていました(つもり)
同じようなしくみで「Cookie(クッキー)」というものがありますが、単純にSessionとの違いは、クライアント側(Cookie)で保存するか、サーバ側(Session)で保存するかの違いです。
今回はSessionを使っています。しかし、Sessionはサーバ側で保持するといっても、クライアント側に簡単な情報を残す、またはそれを送信してもらわなければ、どのユーザーがどのセッションなのか紐付けることが出来ません。できたらそのサーバはエスパーですね。
Sessionの紐付け方法
- レスポンス毎にSessionIDをhtmlでinput hiddenで書き込み、リクエストパラメータとしてやり取りする。
- クッキーとしてSessionIDを保存する。
1はあんまりオススメ出来ません。バレバレですからね。(Cookieもバレバレといえばバレバレですが)
しかし、環境によってはCookieが使えない場合もあるので、その場合は1の手法を利用します。
考察
仕組みと手法までわかった今。
ということは、やはりブラウザ側ではクッキーが存在するんじゃね?
探してみる&試して見る。
CakePHPのセッション管理
ソースリーディングしてみる
また、ソースも確認してみた。$this->Session->destroy()
などは、Controllerから利用できるので、~/cakephp/lib/Cake/Controller/
の中にあると思います。
ソースリーディングする前に、探す目的を用意。じゃないと時間がかかるので。。。
ちなみにSessionController.phpは、ModelにあるCakeSession.phpのインターフェースみたいになっていました。こういう使い方もできるのね。勉強になります。φ(..)メモメモ
~/cakephp/lib/Cake/Controller/Component/SessionComponent.php
<?php // 〜 省略 〜 /** * Used to read a session values for a key or return values for all keys. * * In your controller: $this->Session->read('Controller.sessKey'); * Calling the method without a param will return all session vars * * @param string $name the name of the session key you want to read * @return mixed value from the session vars * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::read */ public function read($name = null) { return CakeSession::read($name); } // 〜 省略 〜
~/cakephp/lib/Cake/Model/Datasource/CakeSession.php
<?php // 〜 省略 〜 /** * Returns given session variable, or all of them, if no parameters given. * * @param string|array $name The name of the session variable (or a path as sent to Set.extract) * @return mixed The value of the session variable, null if session not available, * session not started, or provided name not found in the session. */ public static function read($name = null) { if (empty($name) && $name !== null) { return null; } if (!self::_hasSession() || !self::start()) { return null; } if ($name === null) { return self::_returnSessionVars(); } $result = Hash::get($_SESSION, $name); if (isset($result)) { return $result; } return null; } // 〜 省略 〜
ちと道がそれてしまった。問題はここだ。
<?php // 〜 省略 〜 Configure::write('Session', array( 'defaults' => 'cake', 'timeout' => 1 )); // 〜 省略 〜
こいつに繋がるところはここね。
~/cakephp/lib/Cake/Core/Configure.php
<?php // 〜 省略 〜 public static function write($config, $value = null) // 〜 省略 〜
<?php // 〜 省略 〜 /** * Get one of the prebaked default session configurations. * * @param string $name Config name. * @return bool|array */ protected static function _defaultConfig($name) { $defaults = array( 'php' => array( 'cookie' => 'CAKEPHP', 'timeout' => 240, 'ini' => array( 'session.use_trans_sid' => 0, 'session.cookie_path' => self::$path ) ), 'cake' => array( 'cookie' => 'CAKEPHP', 'timeout' => 240, 'ini' => array( 'session.use_trans_sid' => 0, 'url_rewriter.tags' => '', 'session.serialize_handler' => 'php', 'session.use_cookies' => 1, 'session.cookie_path' => self::$path, 'session.save_path' => TMP . 'sessions', 'session.save_handler' => 'files' ) ), 'cache' => array( 'cookie' => 'CAKEPHP', 'timeout' => 240, 'ini' => array( 'session.use_trans_sid' => 0, 'url_rewriter.tags' => '', 'session.use_cookies' => 1, 'session.cookie_path' => self::$path, 'session.save_handler' => 'user', ), 'handler' => array( 'engine' => 'CacheSession', 'config' => 'default' ) ), 'database' => array( 'cookie' => 'CAKEPHP', 'timeout' => 240, 'ini' => array( 'session.use_trans_sid' => 0, 'url_rewriter.tags' => '', 'session.use_cookies' => 1, 'session.cookie_path' => self::$path, 'session.save_handler' => 'user', 'session.serialize_handler' => 'php', ), 'handler' => array( 'engine' => 'DatabaseSession', 'model' => 'Session' ) ) ); if (isset($defaults[$name])) { return $defaults[$name]; } return false; } // 〜 省略 〜
見つけました。ここですね。defaultのconfig内容を取り出して、後程、core.phpに記述した内容をHash::merge
で配列をマージ(ちょっと違うけど、ドキュメントを参照してくれ!)しています。
パラメータ毎にデフォルトの内容が違うので、設定したcakeだけ追えばいいかな。ここを確認すればよさそうですね。
<?php // 〜 省略 〜 'session.cookie_path' => self::$path, 'session.save_path' => TMP . 'sessions', // 〜 省略 〜
『省略』って字がだんだんうざくなってきましたね。。。
ということで、セッションデータを確認するため、ログを出力してみます。
ログを出力
どこに情報があるかわかりましたので、ログを確認してみます。
<?php // 0 を 2に変更 Configure::write('debug', 2);
すると。
あれ?
なんか変なエラーがちらほら。。。。?(°ω°
・・・・・?
・・・・・・!
`;:゙;`;・(°ω° )ブッ!!
・・・実はこの認証の話。簡易的なコンポーネントを用意していました。また、仕様変更の依頼が来ていたので、それを適応したんですが、、、
とあるコンポーネント
<?php 〜 省略 〜 public function checkAuth($authArray) { // 呼び元は引数2つ $check = $this->checkIdAndPasswd($authArray['id'], $authArray['passwd']); if ($check) { return true; } return false; } // メソッドは引数1つ private function checkIdAndPasswd($passWd) {
呼び元の引数とメソッドの引数が間違っていますorz
ゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴゴ!!!!!!!!!(#・∀・)
(゜∀。)ワヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャ
一人オフィスで発狂しましたとさ(´;ω;`)
衝(笑)撃のラスト & 学んだこと
- うまくいかないときは、debugレベルをあげてみよう。まずはそれで確認してみましょう。
- セッションは意外に単純な仕組みなので、CSRF(クロスサイトフォージェリ)に注意。これはSecurityコンポーネントで対策できます。
- ソースリーディングいいね!( ・∀・)イイ!! 結構勉強になるので、今度もうちょっと読んでみよ。
- IDEを使ったほうがいいのかな。
セッションを学び直し、CakePHPを一部ソースリーディングした結果。知識のレベルはあがりましたが、時間の使い方はNGだったとねorz
(´;ω;`)ブワッ
ちなみにですが、最初うまくいかなかった問題について、先程の不具合を修正したら全部予想通りに動きました! ワロタwwwwwwwwwwww
・・・・ワロタ
(´;ω;`)ブワッ
終わり