がるの健忘録

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

技術メモ:認証変

認証系を作り直しているので、備忘録兼ねて。


とりあえず
・パスワードの持ち方を変えつつ
・セッションIDにmcryptを使わないように
してみやう。…いやmcryptは捨てがたいのだが(苦笑)、オプションとして。


・パスワードの持ち方
以前はsha1でハッシュしていたのですが(何がしかの暗号ロジックを使うことも考えたのですが。… http://d.hatena.ne.jp/gallu/20060731/p3 うわぁ2006年って何年前よw)
ちょいと「一意じゃないお塩で味付け」しつつ「柔軟体操」をしてみようか、と。


・・明日に向かってその1:お塩
ソルト(salt)っていいますねぇ普通。
対象文字列の前後どっちかに(普通前かなぁ? あんまり後ろって見ないような…なんで?)、いらん文字列を付けます。この文字列が「お塩」。
うちでは「ユーザさんは固有のID持ってる」んで(普通そうか)、ユーザIDをお塩につかいます。
お塩で味付けをすると
→レインボーアタックが出来ない http://d.hatena.ne.jp/gallu/20071211/p1
というメリットがあり、またユーザごとに違うお塩にすると
→「同一パスワード」でも出力(保存される文字列)が異なるので、より推測がしにくい
なんてメリットもあります。


・・明日に向かってその2:柔軟体操
ストレッチいいます。上述の「お塩大作戦」だと、いわゆる「ブルートフォース(Brute Force:総当り/力ずく)」な攻撃には無力です。
なので、ストレッチっていう方法を使って「クラック時間を少し延ばします」。あくまで「少し延ばすだけ」なので、そんなに過信されてもまぁ困るのですが。
参考は…わかりやすいあたりですとこちら。
〜 ハワイより 〜 Mikeのプログラミング・メモ
http://blog.makotoishida.com/2011/03/blog-post.html
頑張って英文読むなら(…頑張らずに読めるようになりたいっていうかまず「ちゃんと読める」ようになりたい orz )
Key stretching
http://en.wikipedia.org/wiki/Key_strengthening


んで…ざっくりググってみたのですが…数千回程度から数万回程度まで、ちょいと幅がある感じですねぇ…どしよ?
とりあえずMagicWeaponでは、きりよく「65536」という数値にしてみます。…でも、ふつ〜のサーバでこれやって、150ms程度で処理がおわる orz 10倍くらいにしたほうがよいのかしらん?
ちょっとデフォルトの数値については、もう少し悩んでみまふ。


とまぁこんな思考過程を経て、「DBに保存するパスワード文字列」は、概ねこんな感じになります。
コードっぽい書き方してますが限りなく「嘘言語」なので、適当に脳内で補完してください。
なお、事前に、idとpassを、文字列で入手していると仮定します。
注:ストレッチ回数を微妙に「ぶらしている」理由は。記憶が定かではない「ストレッチ回数もユーザごとに可変なほうがより好ましいって誰かが言ってたような気がする」的記憶によります。理由が定かではないので削除ってもよいのですが、とりあえず書いてみると、是非のどちらに拠らず、なにか突っ込んでいただけるんじゃかなろうか、的な甘くて淡い期待を元に、残しておきます(笑

stretching_num = ( hash_md5(id) % 0xff ) + config(stretching_num, default:65536);

loop stretching_num
 pass = hash_sha512(id + pass);
pool

hashed_pass = pass;


後は、ここで書く内容でもないのですが「パスワード固定、IDをぶん回す系総当り攻撃」用のギミックも用意しておきたいなぁ、っと。
アラート鳴るだけでもなにか違うっしょ。たぶん。


おちゅぎ。セッションID。
セッションIDのベースになるのは、MagicWeaponの中にある「トークナイザ」ってやつです。
この子は
・現在のエポック秒
・現在のミリ秒
・現在のプロセスID
・乱数
から、概ね「一意な文字列」を作り出します。その気になると「自分のIP」も足せるので、並列させてもまずもって一意なんじゃなかろうか、と。
推測不能性については概ね「乱数」部分に頼ってる気がするので、今度この辺を「暗号学的に安全性の高い擬似乱数」に差し替える予定です。
…いつにしよう?


で。
いやまぁトークン自身が丈夫ならそれでいい気もするのですが、現在は
・セッションID(の前後にソルトぶち込んだ文字列)を暗号化(具体的にはRijndael 256)した文字列
を使ってます。
これだと、まず「Rijndael 256の解析コスト」があるので&セッションIDのデフォルト寿命が10分なので、比較的安全性は担保されるんじゃなかろうか、と。少し重いけど。


ただまぁ、PHPだとmcryptライブラリいれなきゃいけなくて、その辺で微妙に不評だったりもしたので。
ちと考えているのが
・セッションIDのベース(トークン)をsha512でハッシュした文字列
にしようかなぁ、とかも考えてます。
うちのトークナイザのトークンは多分レインボーテーブルには入れにくいのですが、一応「お塩&ストレッチ」は「オプション的に考慮」してみようかなぁ、とかなんとか。


こっちもなんか「ブルートフォース系」への対策をしておきたいような気がするのですが…DDoSまでを視野に入れたときに…どうしようかなぁ? と。
とりあえず「いい手があったらやる」程度に備忘録。


まぁ基本的に「ガチャコン構成(気に食わなかったら、インタフェースあわせた「別クラス」に差し替えられる構成)」にするつもりなので。
「まずいってわかったらその時点で改修すりゃいいや」的に楽観視はしているのですが。
# きっと親切な おもひかね が突っ込んでくれるって信じてる。


以上、明らかにメモ(笑

フレームワークは思想

「このフレームワークを導入したからうまくいくぞ!!」って、どこの「銀の弾丸伝説」でしょうか?
フレームワークは、元々、作者の「こーゆー風に物事をやりたいつくりたい」って思いがあって、「その思いの補助道具」として存在してるざます。


あなたが使ってるフレームワーク
その作者は「どんなお困りごとがあって」「どんな思想があって」そのフレームワークを作ったんですか?
それを知らずに理解せずに調べようともせずにつかっているなら。


きっと、お道具に振り回された挙句に「つかえねぇなぁ」ってなるんじゃないですかね?
使えないのは、お道具なんだか道具に振り回されてる人間様なんだか。

「似非DIコンテナのようなものもどき」作りました〜

もっそ微妙w
メモかねて。


先に使い方。
・configに「di_config」でDI用の設定ファイル名を書く
・di_configの書式例

# 仮想クラス名 = includeファイル名:newしたいクラス名
#-------------------------------------------------------

# 基本書式
cgi_request = cgi_request_with_emoji.inc:cgi_request_with_emoji

# 省略書式その1。includeファイルは「クラス名 + .inc」
view = :view_mobile

# 省略書式その2。includeファイルは「設定したディレクトリ + クラス名 + .inc」
hoge = common/:hoge_advance

で、使用例。
include(正確にはrequire_once)はDI側でやってくれるので気にせず。

// インスタンスげと〜
$obj = DI::create('hoge');

// staticなクラスの場合(5.2-
call_user_func( array(DI::get_name('hoge'), 'callしたいメソッド名')[, 引数があれば]);

// staticなクラスの場合(5.3+
// XXX 未テスト。もしかしたら一回、名前を変数に入れないとダメかもしれない
(DI::get_name('hoge'))::callしたいメソッド名(引数があれば);


んで、裏側にあるもにょもにょ。
まず初めに。「あんたDIのことdisってたよねぇ http://d.hatena.ne.jp/gallu/20060822/p2 」という話は甘んじてうけますっていうか今でもあんまりその辺のスタンスは変わらず。
ただ一方で http://d.hatena.ne.jp/gallu/20071218/p2 にも書いたとおり「一部では」使いやすいことに気づいて。
で…その「一部」ん中に、フレームワークがあることに気づきました。


っても、そんなにごっつくたいしたことやっているわけではぜんぜんないゆえんが似非だったりようなだったりもどきだったりするゆえんですが。
えと…例えば、こんな1文があります。

$obj = new cgi_request();

ここで「やっていること」は「cgi_requestクラスのインスタンスを作っている」のですが。
ここで「やりたいこと」は、別に「cgi_requestクラスのインスタンスを作りたい」わけではなくて、厳密には「CGIのrequestを包括してあつかってくれるようなもにょもにょなクラスのインスタンスを作りたい」わけですよね?


なので。
今回、DIコンテナっぽいものを作って、この辺を一段、抽象化してみたという寸法です。


リアルソースは一両日中くらいに上げておきますんで、質問その他あったらよろです。
一応、既存のと互換性保てるようには作ったつもりではあるのですが。もしかしたら微妙に怪しい可能性が、否定はできないので。

data clumpについて

最近、むやみやたらに進化してきているdata clumpなのですが。
これを一言で言い表すよい言葉を思いついたので、メモ。


Object-Table Mapping


元ネタは言わずとしれたObject-Relational Mapping。
data clumpの細かい話は、また後日〜

いくつか

いち。
mapファイルで@includeを使えるようにしました!!
注意点としては「カレントディレクトリは、map.txt本体が置いてある場所」って事くらいかな?
レポジトリにあげなきゃいかんですが、これで本格的に「レ〜ゴレゴ」な世界に突入出来そう!!
パーツ群は乞うご期待w


に。
携帯でIPチェックせざるを得ない状況で(まぁDoCoMoJavaScriptの話もあるし、いずれにせよ契約者固有IDは近々に全面廃止になりそうですがね B-p)。
PCとの混在だと、単純にhttpd.confに書くってのも色々と厄介なので。あんど、ほかにも「一瞬だけIPで絞りたい」的な要求は案外に多いので(それが是か非かはまたともかくとして、一つのカードとしては重要なので)。
とりあえず比較的評判がよいと思われる、洋梨のNet_IPv4を使おうかと思ってソースを紐解いたのですが…double型前提ってどゆことよ orz
やっぱり洋梨ってば用無し… orz


すみませんとりあえず古い人間なんでdouble型は信用出来ないので。やむなく、自作の道に至りました orz
現在絶賛作成中。とりあえず「1つのIPアドレスを意味するクラス」と「ユーティリティ系クラス」という、相も変わらずひねりのない構成に仕上がっております。
「1つのIPアドレスを意味するクラス」は、内部の情報の持ち方次第で「GMPクラス」と「(やむを得ずなので)doubleのクラス」を用意。まぁほかの型がよければ適宜継承してって感じ?


ああ、一応念のため(突っ込まれてから書くのも面倒だし)。
http://php.net/manual/ja/language.types.float.php

よって、小数の最後の桁を信用してはいけませんし、 小数が等しいという比較を行ってはいけません。より高い精度が必要な場合には、 任意精度数学関数または gmp 関数を代わりに使用してください。


さて…また、そろそろWeponの進化が始まりそうである!!

雑に追加

以下の項目をconfigに追加〜

# 携帯のみ有効とする
only_mobile = on
no_mobile_uri = ./no_mobile.html
no_uid_uri = ./no_uid.html

user-agent見てまふ、なのである部分注意。


&おまけ


DoCoMoで「入り口だけguidチェック」するなら。
かなりあちこち雑なコードだけど、例えばこんなん。

// XXX
$mobj = new mobile_info();
if ('' === $mobj->get_sid()) {
  if (true === $mobj->is_docomo()) {
    if ( (false === isset($_GET['guid']))&&(false === isset($_POST['guid'])) ) {
      header('Location: ./index.php?guid=on');
      exit;
    }
  }
}

まぁ。guid=offとか書く人も大抵いないでしょ、って前提。
query_stringだのpostパラメタだのその他気にする人がいたら適宜自分で修正して〜 ノ

認証系設定の仮まとめ

認証の基本知識はこっち見て。
http://d.hatena.ne.jp/gallu/20080203/p1


以下、authentication(個体認証)。
基本、login.incとかいうブツん中にあるざんす。メソッド位置的にはpublic function initialize() 内。
一般的な、ID+Passwordでのログイン:front用なので、email + passになる。

  // 本人認定の種類
  // ID + Password
  $this->authentication_type_ipass();

  // 本人認証の設定各種
  //$this->set_cgi_name_id();
  //$this->set_cgi_name_pass();
  //
  //$this->set_client_clump_name();
  //$this->set_auth_user_clump_name();
  //
  //$this->set_password_hash_type('sha-1');
  $this->set_authentication_user_clump_name('auth_user_clump');


管理画面系の、auth系テーブルのIDを直に使う系

  // 本人認定の種類
  // ID + Password
  $this->authentication_type_direct_ipass();

  // 本人認証の設定各種
  //$this->set_cgi_name_id();
  //$this->set_cgi_name_pass();
  //
  //$this->set_client_clump_name();
  //$this->set_auth_user_clump_name();
  //
  //$this->set_password_hash_type('sha-1');
  $this->set_authentication_user_clump_name('auth_admin_user_clump');



  // initialize で認証するから、より上位で設定を先にしてから parent をcall
  parent::initialize();


以下、authorization(認証状態の継続)。
大抵、commonにある「各基底クラス」のinitializeメソッドでやるよねぇ。


Cookieによる認証維持。

  // 認証継続の種類
  $this->authorization_type_cookie();

  // 認証継続の設定
  //$this->authorization_cookie_name('k');
  $this->set_authorization_crypt_key('any crypted key string');
  $this->set_authorization_expire_flg(1);
  $this->set_authorization_expire(60 * 60);
  $this->set_authorization_clump_name('session_clump');

  // initialize で認証するから、より上位で設定を先にしてから parent をcall
  parent::initialize();


携帯にありがちな「契約者固有ID」での処理

  // 認証継続の種類
  $this->authorization_type_contractor_id();

  // 認証継続の設定
  $this->set_login_error_command('error');

  // initialize で認証するから、より上位で設定を先にしてから parent をcall
  parent::initialize();


以上本気でただの覚え書き。