Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Webアプリケーションにおけるパスワードの管理について

mrtc0
September 12, 2016

 Webアプリケーションにおけるパスワードの管理について

#LT駆動 29での発表スライド

mrtc0

September 12, 2016
Tweet

More Decks by mrtc0

Other Decks in Programming

Transcript

  1. 背景 • パスワードをDBに保存するときに、具体的に どう保存すればいいのか – ハッシュ化 + ソルト – 使用するアルゴリズムはどれにすべきか?

    – ちゃんと整理したい • 昨日の深夜にサクッと作ったので気軽にマサカ リ投げてください • Djangoでどういった実装がされているのか
  2. Case 1 • パスワードを平文のまま保存 +------+--------+------------+ | id | name |

    password | |------+--------+------------| | 1 | admin | password | +------+--------+------------+
  3. Case2 • DB内でパスワードを暗号化 +------+--------+------------------+ | id | name | password

    | |------+--------+------------------| | 1 | admin | 402fda0cde783273 | +------+--------+------------------+
  4. 暗号化して保存 • Ad be ◦ が過去に採用していたケース • 暗号化されて安全だね!やったー! – とはならない

    • 暗号化するプログラムが入手されたら? • 同じパスワードからは同じ文字列が生成される
  5. Case3 • パスワードをハッシュ化して保存 +------+--------+----------------------------------+ | id | name | password

    | |------+--------+----------------------------------| | 1 | admin | 5f4dcc3b5aa765d61d8327deb882cf99 | +------+--------+----------------------------------+
  6. Case4 • ハッシュ + ソルトを使用 +------+--------+--------------------------------+ | id | name

    | password | |------+--------+--------------------------------| | 1 | admin | $1$salt$qJH7.N4xYta3aEG/dfqo/0 | +------+--------+--------------------------------+
  7. ハッシュ+ソルト • 16byte以上のソルトを使用すること • ランダムなソルトを使用 – random()は使わない – CryptAPIとか/dev/urandomとか •

    これで同じパスワードから同じハッシュ値が生 成される問題はなくなった • だいぶ堅牢になったぞ!!!!!
  8. ストレッチング • ハッシュ + ソルトな方式を使用することで かなり堅牢になった • しかし、まだだ!!! • 最新GPUを大量に積めば一瞬で大量のSHA-

    256 Hashを計算することも可能 – 最近ではAWSに金をつぎ込むことでも可能! • 現実的に計算できないようにするためにスト レッチングを行う
  9. PBKDF2 • KDF(Key Derivation Function) – 鍵導出関数 – 固定長で一定のエントロピーを持つより安全な鍵を 得ることが可能

    – パラメータに繰り返し回数があり、計算量を調整で きる • PBKDF2はRFC2898に基づたKDF
  10. PBKDF2 • DK = PBKDF2(PRF, Password, Salt, c, dkLen) –

    PRF : 疑似乱数生成関数. HMAC – Password : パスワード – Salt : ソルト – C : 繰り返す回数 – DkLen : 出力する導出鍵の長さ
  11. MD(Message Digest) • 所謂、一方向ハッシュ関数 – 任意のメッセージから固定長メッセージを生成 – admin → 5f4dcc3b5aa765d61d8327deb882cf99

    • 異なるメッセージから同一のハッシュ値を生成 することが困難でなければいけない • ちなみにCRC32のような誤り検出符号は暗号 的ハッシュ関数とは区別される
  12. MDとMAC • MD ... メッセージを容易に計算できる • MAC … 共通鍵がなければ計算できない •

    共通鍵なので否認を防止することができない • つまり、メッセージを生成したものが本人であ るという保証はされない
  13. HMAC • ハッシュ関数 + MAC • すべてのハッシュ関数に適用可能 – それぞれHMAC-MD5とかHMAC-SHA1とか •

    他にもCBC-MACなどもある – ブロック暗号アルゴリズムと組み合わせる方式 – OMAC/CMAC, PMAC
  14. PBKDF2 • DK = PBKDF2(PRF, Password, Salt, c, dkLen) –

    PRF : 疑似乱数生成関数. HMAC – Password : パスワード – Salt : ソルト – C : 繰り返す回数 – DkLen : 出力する導出鍵の長さ • で、何回繰り返せばいい???
  15. Djangoの実装を見てみる • Djangoでは標準で、ユーザーのパスワードを PBKDF2で保存している from django.contrib.auth.models import User user =

    User(username="user") user.set_password('password') user.password 'pbkdf2_sha256$24000$NPCTHzvjHgPo$phHqNmNOafrNsxYXZm2HNpPBXzqBVijvakAFVkR HbZs='
  16. 計測してみた • i5-2520M 2.50GHz – 64文字と10000000文字(10MB)で試す from timeit import timeit

    setup = ''' from django.contrib.auth.hashers import PBKDF2PasswordHasher hasher = PBKDF2PasswordHasher() password = "A" * 10000000 salt = "salt" ''' result = timeit(stmt = 'hasher.encode(password = password, salt = salt, iterations = 24000)', setup=setup, number=500) print(result)
  17. まとめ • パスワードを保存する際には以下の要件を必ず満たす 必要がある – 管理者でもユーザーのパスワードを復元できない – 同一パスワードから同一ハッシュ値を生成しない • 具体的には

    – 疑似乱数発生関数である程度の長さのソルトを使ってハッ シュ値を生成する – KDFで十分な回数繰り返す • WAFでは標準で実装されていたり、ライブラリも充実 しているので積極的に頼っていくべき