パスワード管理について「安全な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 モジュール漁る時に、とりあえずこちらの目次を見ながら探しましたよっと。

いじょ。