Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

パスワードの保存方法

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

21 ソルトのイメージ

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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のイテレーション数

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

速度比較 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

Slide 35

Slide 35 text

速度比較(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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

Password Recovery 39

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

使い方 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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

デモ 44

Slide 45

Slide 45 text

45

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

47 そのほか

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

50 まとめ

Slide 51

Slide 51 text

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