ITの隊長のブログ

ITの隊長のブログです。Rubyを使って仕事しています。最近も色々やっているお(^ω^ = ^ω^)

目の前のバグに気が付かず、セッションを学び直し、CakePHPをソースリーディングした話

スポンサードリンク

http://www.flickr.com/photos/39038071@N00/318123668
photo by TheGiantVermin



(とてもくだらない記事なので暇な人だけよむことをオススメします)




簡単なAuth認証を自作しました。


それで、セッションのタイムアウトの時間を設定するため、CakePHPのセッションを設定してみると、不可解な現象が発生した。

環境とファイル

用意したファイル

~/cakephp/app/Config/core.php

// 〜 省略 〜
	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)


www.geocities.jp



一応基礎は知っていました(つもり)


同じようなしくみで「Cookie(クッキー)」というものがありますが、単純にSessionとの違いは、クライアント側(Cookie)で保存するか、サーバ側(Session)で保存するかの違いです。



今回はSessionを使っています。しかし、Sessionはサーバ側で保持するといっても、クライアント側に簡単な情報を残す、またはそれを送信してもらわなければ、どのユーザーがどのセッションなのか紐付けることが出来ません。できたらそのサーバはエスパーですね。

Sessionの紐付け方法

  1. レスポンス毎にSessionIDをhtmlでinput hiddenで書き込み、リクエストパラメータとしてやり取りする。
  2. クッキーとしてSessionIDを保存する。


1はあんまりオススメ出来ません。バレバレですからね。(Cookieもバレバレといえばバレバレですが)


しかし、環境によってはCookieが使えない場合もあるので、その場合は1の手法を利用します。

考察


仕組みと手法までわかった今。


ということは、やはりブラウザ側ではクッキーが存在するんじゃね?


探してみる&試して見る。

検証

Google Developer Toolsで削除する


冒頭でやりましたね。セッションデータが増えました。恐らく別にセッションが作成されたと思います。



何故かログインは継続していますが・・・・(´ヘ`;)ウーム…

ブラウザのキャッシュ&クッキー等、履歴を全部削除


Chromeの手順の通り、全部削除しました。(あとからSNSログインなどめんどくせぇ!)


アクセス!


ログイン継続中(´;ω;`)ブワッ

もう、設定がまちがっているんじゃね?


これしかないでしょ。じゃないとこれまでのセッションの基本がガン無視されている!


そもそも、CakePHPのセッションの仕組みってどういう管理なんだろ?次に続きます。

CakePHPのセッション管理

ドキュメントを読んでみる


セッション - 2.x



あんましよくわからない。


いや、そのとおりに設定しているのにナゼ動かない?

ソースリーディングしてみる


また、ソースも確認してみた。$this->Session->destroy() などは、Controllerから利用できるので、~/cakephp/lib/Cake/Controller/の中にあると思います。


ソースリーディングする前に、探す目的を用意。じゃないと時間がかかるので。。。

  • core.phpで、Sessionの設定に必要な値(php、cake、database、cache)の意味を調べる


ちなみに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;
	}

// 〜 省略 〜

ちと道がそれてしまった。問題はここだ。


~/cakephp/app/Config/core.php

<?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






・・・・ワロタ






(´;ω;`)ブワッ



終わり