パスワード管理について「安全なWebアプリケーションの作り方」で学んだので実装してみた

前回半分くらい読んで積読になってしまっていた「徳丸本」こと「安全なWebアプリケーションの作り方」を週末に読みきりました。本当にいい教科書だと思いますので、脱初心者を目指す人は読んでみると良いと思います。

特に今までぼんやりとしか理解していなかった「パスワード管理」について非常に体系的に分かりやすく説明されていたので、せっかくなのでPlackアプリで実装してみました。ソースはgistに貼っておきました。

基本的には徳丸本にあったとおりに実装しています。

  • パスワードはハッシュをかけた値をDBに保存
    • 但し単純なハッシュ関数だと漏洩したときにクラックされる(=逆方向に解析される)
    • そこで2つの対策を組み合わせる
      • salt値
        • user_idと固定値を利用してsalt値を作りパスワードに付加してハッシュを取る
        • もし同じパスワードのユーザがいてもハッシュ値は異なる
      • ストレッチング
        • 何回もハッシュ関数をかけることで総当たり攻撃に強くする
    • CPANのAuthen::Simple::DBIを使ってみた
      • すでに持ってるDBIハンドルを渡せないのがたまにきず
      • 第2引数は、リクエストパラメータに上記の操作を行った結果のハッシュ値を渡せばよい
    • saltの部分はCrypt::SaltedHashも検討
      • 徳丸本では明確なメリット無しと書いてあったsaltをハッシュと一緒に保存する方法だったのでとりあえずパス
  • 自動ログインの為にセッションIDのexpiresを伸ばすのではなく、tokenを使う
    • Plack::Middleware::Sessionは多分expires設定できるので不要と言えば不要
    • ただ、HTTPSとの組み合わせなどで使いたい場面はあるかも知れない
    • tokenの値はbase64ではなく普通にunpackした
      • base64だとCookieの方が微妙にURLエンコードされてしまったので
    • tokenの方にはexpiresを設定しているので、ブラウザ再起動したり直接セッションIDを消してもログインが継続
      • DBにtoken,user_id,expiresを記録しておいて適切に処理
    • Math::Random::MTも検討してみた
      • 正直乱数よくわからなかったので、とりあえず/dev/urandomを使う徳丸本のやり方で
  • ログアウト時は一応CSRF対応
    • ログアウトはPOSTのみとして、そのhiddenパラメータにセッションIDそのものを入れる
    • リクエストが来たらhiddenパラメータとセッションIDを比較してからログアウト
  • Plack::Middleware::Auth::Formはちょっとイマイチ
    • 簡単なユーザ管理を想定してミドルウェアでできないかなと思って使ってみた
    • まぁいいとは思うんだけど、ログアウト時にセッションIDがそのままなのはちょっと危険なのかなーと思った
      • 具体的にどこが危険なのかは分からないけどなんとなく。
    • もうちょっとカスタマイズできると、バックエンドアプリとかで使いやすいかも

色々適当に作ったけど、とりあえずやりたいことはできたので満足。真面目に作るの本当に大変だなぁ。てか、はやくCPAN本が手元に欲しいっす><

CPANモジュール漁る時に、とりあえずこちらの目次を見ながら探しましたよっと。

いじょ。