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

djangocongressjp2023_password_hash

bungoume
October 06, 2023

 djangocongressjp2023_password_hash

bungoume

October 06, 2023
Tweet

More Decks by bungoume

Other Decks in Programming

Transcript

  1. DjangoCongress JP 2023
    梅崎 裕利 (@bungoume)
    Djangoのパスワードハッシュ

    View Slide

  2. 2
    自己紹介
    ❏ Yuri Umezaki (@bungoume)
    ❏ 検索API (Elasticsearch, Django)
    ❏ OAuth認可 API基盤
    ❏ アクセスログ分析

    View Slide

  3. 自分のパスワードが流出しているか確認
    3
    HaveIBeenPwned.com
    https://haveibeenpwned.com/

    View Slide

  4. 4
    ● パスワードだけが守るべき対象ではないが...
    ○ ユーザーの権限を利用されてしまう
    ○ パスワード漏えいは他のサービスにも影響を与える
    大手IT企業でも起きており、他人事ではない
    過去の事例を教訓に活かすことが重要
    過去の事件を教訓に

    View Slide

  5. パスワードの保存方法

    View Slide

  6. 6
    ● パスワードハッシュとは
    ● パスワード長と解析速度
    ● 各パスワードハッシュの紹介
    ○ Djangoでのデータ内容
    ○ Djangoにおける歴史
    ● 計算時間の比較
    ● ハッシュ解析
    アジェンダ

    View Slide

  7. 7
    ● ハッシュ化とは、辞書において
    "細かく刻む、切り刻む、細切れにする"
    ● ハッシュ値はデータを固定長の値に変換したもの
    ○ 同じ値からは同じハッシュが作られる
    ● パスワード文脈では
    ○ 漏洩後にパスワード悪用をできるだけ遅らせたい
    パスワードのハッシュとは

    View Slide

  8. 8
    ● 両方とも、機密データを安全に保つ方法
    パスワードは暗号化ではなくハッシュ化する必要がある
    (ほぼすべてのケースでハッシュ化が必要)
    ハッシュと暗号化

    View Slide

  9. 9
    ● ハッシュは一方向関数
    ○ 復号して平文を取得することはできない
    ○ ハッシュを取得してもそのままログインには使えない
    ○ (取得はできないが解読はできる。後述)
    ● 暗号化は双方向
    ○ 元の平文を取得可能
    ハッシュと暗号化

    View Slide

  10. 10
    ● 長いパスワードは利用者にとって手間
    ● 種類が少なければ、ハッシュといえど総当りで復元可能
    ○ →あえて計算に時間がかかるようにする必要がある
    人間の思いつくパスワードは限定的

    View Slide

  11. 11
    IPAのコンピュータウイルス・不正アクセスの届出状況 (2008年10月)
    https://www.jacic.or.jp/topics/2008100201/ipa_200809.pdf
    によると、
    > 解読には最大で約50年
    > 3種類(62文字数)で8桁のパスワードを作成すればパスワードの強度は十分
    ・・・では今は?
    よくあるパスワード長の根拠

    View Slide

  12. 12
    オフライン攻撃想定
    MD5をGeForce RTX2080
    (40GH/sec)で計算した場合の時間
    8桁の英大小文字+数字で1時間
    ● 2023最新のRTX 4090は150GH/secなので更に約¼
    ○ 9桁の英大小文字+数字が約1日
    2020 パスワード総当り 必要時間表
    https://www.response-it.co.uk/news/2020/9/2/how-long-does-it-take-to-crack-your-
    password
    https://openbenchmarking.org/test/pts/hashcat

    View Slide

  13. 13
    2008年に比べてCPU性能は向上。
    GPUによる計算も広まり、10万倍近くのハッシュ計算性能が簡単
    に出せるように。
    また、暗号通貨系で広まったASIC等がパスワード解析に利用さ
    れると更に大幅に高速となる可能性もある
    計算性能向上・GPGPU、ハードウェア化

    View Slide

  14. 14
    利用者
    ● パスワードは使い回さない/長いパスワード
    ● パスワードマネージャを使うのも手
    システム側
    ● 計算に時間の掛かるパスワードハッシュ関数を利用
    ● ハードウェア化を行いにくくする
    ● (世の中的に正しいとされる設定を使う)
    どうすればよいの

    View Slide

  15. 15
    各ハッシュアルゴリズムの概要

    View Slide

  16. 16
    現時点でのセキュリティ上
    ベストな設定が色々掲載
    https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
    OWASP Cheat Sheet

    View Slide

  17. Django4.1まで 使えたハッシュ関数
    17
    PASSWORD_HASHERS

    View Slide

  18. Django4.2 標準で使えるハッシュ関数
    18
    PASSWORD_HASHERS

    View Slide

  19. 19
    ● Argon2
    ● pip install argon2-cffi
    ● settings.py に以下の設定を入れればOK
    ○ (先頭のものが利用されます。2つ目以降は移行用)
    おすすめの設定

    View Slide

  20. 20
    ソルト
    ● 各パスワードに追加される、ランダムな一意の文字列
    ● パスワードごとに別の値
    目的
    ● レインボーテーブル(事前計算されたハッシュDB)を使った解読
    の保護
    ● 大量ハッシュの同時解読難化
    ● パスワードが同じ人の特定を防ぐ
    用語: ソルト(salt)

    View Slide

  21. 21
    ソルトのイメージ

    View Slide

  22. 22
    ● ソルトに加えて利用するシステム共通の文字列
    ● データベース以外に保存
    目的
    ● DBのデータのみが流出した際の解読リスクを減らす
    用語: ペッパー(Pepper)

    View Slide

  23. 23
    ● 計算コストを増やす目的
    ● 何度も繰り返しハッシュ化し元データ推測を困難にする
    ● 数十万回行うことも
    ● ストレッチ回数: iterations
    用語: ストレッチング
    mypassword 91dfd9dd… fabe5482… 83d5743b…
    ハッシュ化 ハッシュ化 ハッシュ化

    View Slide

  24. 24
    よく使われるのは
    Modular crypt format (MCF)
    $6$SALT$bWoY9tMqAn7I9eJU/mmCZoOL6wokwfHgWBWRvbDrUMpmMpNk
    /zyQaJe70FiLSvJyzi9lB6GtoivF1/NMwymZa1
    Linuxの/etc/shadowなど
    https://passlib.readthedocs.io/en/stable/modular_crypt_format.html
    ハッシュ化したパスワードの保存形式

    View Slide

  25. 25
    ● auth_userのpassword field(char 128)に格納
    ● $区切り
    ● 先頭はハッシュ方式
    ● その後、パラメータとハッシュ(詳細は各関数に異なる)
    例: [タイプ]$[ストレッチ回数]$[ソルト]$[ハッシュ]
    Djangoにおけるパスワードデータ
    pbkdf2_sha256$360000$dNhx87pKlB9E$xKRyAEunJkChipeBH
    aIbSNipBUOSTvUcqMUFrvz9UEI=

    View Slide

  26. 歴史
    26
    Django1.4 から設定でハッシュ関数が変えられるように
    v0.91の段階でpasswordデータは先頭がハッシュ方式
    [タイプ]$[salt]$[hexdigest]
    なので、アルゴリズム変更が可能
    https://www.djangoproject.com/weblog/2005/nov/20/passwordchange/

    View Slide

  27. 27
    ● PBKDF2
    ● bcrypt
    ● scrypt
    ● Argon2
    紹介するパスワードハッシュ関数

    View Slide

  28. PBKDF2
    28
    ● Djangoのデフォルト方式で、よく利用される
    ● ライブラリ不要
    ● iterationsを増やすのが容易
    ● NIST FIPS-140 で推奨
    [タイプ]$[ストレッチ回数]$[ソルト]$[ハッシュ]
    pbkdf2_sha256$720000$FkxESIA1MrrH$EXYJuJLVXjJ8A+MLGKJ9bfQ2HWr1mRhcB2tlSHyWiG4=

    View Slide

  29. 29
    イテレーション回数はバージョン更新ごとに増加
    v1.4-1.6: 10000 ->v1.7: 12000 …
    -> v2.0: 100000 -> v2.1: 120000 …
    -> v4.2 600000 -> v5.0 720000
    https://docs.djangoproject.com/en/dev/internals/howto-release-django/#new-stable-branch-tasks
    > New stable branch tasks Increase the default PBKDF2 iterations in
    > django.contrib.auth.hashers.PBKDF2PasswordHasher by about 20%
    PBKDF2のイテレーション数

    View Slide

  30. SHA256+bcrypt
    30
    ● Blowfishという古い暗号化方式を利用
    ● ハードウェア化が難しいとされる
    ● iterationsで計算量を増やすことが可能
    ○ 必要メモリ量の調整はできない
    ● BCryptPasswordHasherはパスワードを72文字で切り捨て
    ● PHPなどの標準方式
    ● 利用事例も多い
    [タイプ]$[タイプ]$[ストレッチ回数]$[ソルト(22文字)][ハッシュ(31文字)]
    bcrypt_sha256$$2b$12$XScV8pd5i/ERqlLx2Q1Ipu2qBGUlc1HorN5Y4mEOurNlt/K6/UC.u

    View Slide

  31. scrypt
    31
    ● Django4.0から利用可能
    ● メモリ使用量を増やし、ハードウェア化を難しくした設計
    ● bitcoinフォークのLitecoinで利用されているらしく、既にある程度
    ハードウェア化されている
    ○ TMTO(Time-Memory Trade Off)等でハードウェア化を防ぎきれなかった
    ○ 選択肢として致命的な問題があるわけではなさそう
    [タイプ]$[メモリ,CPUコスト]$[ソルト]$[ブロックサイズ]$[並列数]$[ハッシュ]
    scrypt$16384$AHnJwIHTDWiUrcEelaZ3i6$8$1$upF27cH+BRCe8QFnTNkby7eN3RuDw/GJslociOjopz
    PIZM4ebz2GPnHLBtZl6ZhRR28p54pL8cm5mPcvBSodcg==

    View Slide

  32. Argon2
    32
    ● Password Hashing Competition(2015.7) 勝者
    ● メモリ使用量を設定するパラメータがある
    ● Djangoで利用にはサードパーティのライブラリが必要
    ○ pip install argon2-cffi
    [タイプ]$[タイプ]$[バージョン]$[m=メモリコスト],[t=タイムコスト],[p=並列数]$[ソルト]$[ハッシュ]
    argon2$argon2id$v=19$m=102400,t=2,p=8$S0JrY1YzVDYwTjg0dlE1UjRvUTllSA$bDLYCv6H6wZ
    mu6ZWjEby0twmI27SApnFEyjyrszNJ9E

    View Slide

  33. Argon2
    33
    ● argon2i サイドチャネル攻撃耐性
    ● argon2d GPUを使った攻撃に対する耐性
    ● argon2id いいとこ取り
    今はargon2idが推奨
    Djangoは3.2よりargon2iからargon2idに変更
    (PHPは7.2でargon2iを導入、PHP7.3でargon2idをサポート)

    View Slide

  34. 速度比較
    34
    設定値 1回あたり Mem
    PBKDF2 iterations = 720000 (v5.0 default) 390 ms 0.0 MiB
    SHA256+bcrypt rounds = 12 (default) 250 ms 0.2 MiB
    scrypt N=2^14(16 MiB), r=8, p=1 (default) 47ms 16.0 MiB
    scrypt N=2^14(16 MiB), r=8, p=5 (OWASP) 220ms 16.0 MiB
    Argon2id t=2, m=102400, p=8 (default) 56 ms 100.4 MiB
    Argon2id t=2, m=19456, p=1 (OWASP) 33ms 19.0 MiB
    ## python version: 3.11.4
    ## python compiler: Clang 14.0.0 (clang-1400.0.29.202)
    ## cpu model: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz

    View Slide

  35. 速度比較(2018の資料, CPUが違います)
    35
    設定値 100回 (秒) 1回あたり
    SHA1+Salt 0.0074 0.01 ms
    PBKDF2 iterations = 100000 12.6987 127 ms
    SHA256+bcrypt rounds = 12 38.6854 387 ms
    Argon2 m=512, t=2, p=2 0.1901 2 ms
    ## python version: 3.6.5
    ## python compiler: GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)
    ## cpu model: Intel(R) Core(TM) i5-4250U CPU @ 1.30GHz

    View Slide

  36. 36
    1. Argon2id
    2. Argon2idが使用できない場合はscrypt
    3. 今使ってる場合はbcrypt
    4. FIPS-140 準拠が必要な場合PBKDF2
    それぞれ安全な設定値で使うこと
    (+多層防御としてペッパーの追加を検討)
    OWASPの推奨値

    View Slide

  37. 37
    ● 古いハッシュ形式・iterationsが少ないユーザーデータ
    ○ Djangoはログインのタイミングで自動的に強化
    ○ スムーズに移行が可能
    ● 最近アクセスしていない人は変更されない
    ■ 長く続いているサービスはバッチで置き換えをする
    ハッシュ関数を変えた後は

    View Slide

  38. django内でのhash関数
    38
    変数
    algorithm, iterations, など
    関数
    encode, verify, safe_summary,
    must_udpate, harden_runtime

    View Slide

  39. Password Recovery
    39

    View Slide

  40. Password Recovery
    40
    パスワードを忘れてしまったとき
    Hashから元の文字列を実際に復元するには

    View Slide

  41. hashcat
    41
    ● 世界最速を謳うパスワードクラッカー
    ● https://hashcat.net/hashcat/
    ● OSS (MIT)
    ● GPU, FPGAなど利用可能
    ● 200以上のhashに対応
    ○ Django (SHA-1)
    ○ Django (PBKDF2-SHA256)
    注: パスワードクラックを推奨するものではありません。

    View Slide

  42. 使い方
    42
    $ sqlite3 db.sqlite3 "SELECT password FROM auth_user;" > django_pass.txt
    $ hashcat -m 10000 -a 0 django_pass.txt
    10-million-password-list-top-10000.txt -O

    View Slide

  43. パスワードリスト
    43
    ● https://github.com/danielmiessler/SecLists
    ● セキュリティ評価のためのユーザ名, パスワードなど

    View Slide

  44. デモ
    44

    View Slide

  45. 45

    View Slide

  46. デモ結果
    46
    ● パスワードリストに載ると一瞬
    ○ パスワードハッシュ関数を選んでも、辞書攻撃には弱い
    ● 利用者には強いパスワードを利用してもらうのが大事
    ○ リストに乗ったものは利用させない
    ○ CommonPasswordValidatorですこしはチェックできる

    View Slide

  47. 47
    そのほか

    View Slide

  48. 48
    オフライン攻撃が容易な箇所は注意が必要
    ● 秘密鍵
    ○ v2のsshkeyやed25519はKDFラウンド数指定可能(-a)
    ● zip
    ○ stretchなし or hmac-sha1×1000ラウンド
    ● Word, Excel
    ○ 2007以降は50000〜100000ラウンド
    DBだけでなくファイルも注意
    参考
    https://www.slideshare.net/herumi/ss-57319518#4

    View Slide

  49. パスワードハッシュで出来なくなること
    49
    ● チャレンジレスポンス型認証
    ○ CHAP
    ○ CRAM-MD5
    ○ DIGEST-MD5
    ● クライアントでワンタイムnonceを使ってハッシュを計算
    ○ サーバー側でも生passwordが必要

    View Slide

  50. 50
    まとめ

    View Slide

  51. まとめ
    51
    ● DjangoのパスワードハッシュはArgon2を選ぶと良い
    ○ 標準の設定(PBKDF2)でも全く問題はない
    ○ Djangoのパスワードハッシュアルゴリズムの変更は容易
    ● パスワードハッシュ計算は以前より時間がかかる
    ○ API用などで都度検証する実装の場合、性能劣化要因になっている可能性
    ● 利用者は強いパスワードを使うこと
    ● 昔から動かしているサービスはハッシュ移行を検討
    ● Password management in Django に詳細

    View Slide