パスワード暗号化について学びを得た
今日はパスワードの暗号化について書いてみたいと思います。
きっかけはSTNSにSudoパスワードを追加した際に@matuuさんよりご指摘をいただいたのがきっかけです。
これまでパスワード暗号化に対する知見が全く無く、「とりあえずSHA256あたりでハッシュ化しとけば漏洩してもダイジョウV!!!」なんて思ってたものですから、これを機に調べてみました。
パスワードの暗号化が有効に働く機会として最も可能性が高いのは、サーバに何らかの手段で侵入され、データベース、ソースコードが参照された状態だと思います。要するに侵入者にすべてを見られた状態でもパスワードを知られ得ないことを目的として暗号化するわけです。
パスワードの暗号化時によく用いられる強固にする手法としてはSalt、Stretchingの2種類があります。今回はこの2点についてまとめてみました。
Saltを利用しパスワード暗号化を強化する
Saltというのは御存知の通り塩です。パスワードに塩を足して、いい塩梅にするわけです。前提となる話として、パスワードクラックの手法の一つにレインボーテーブルを用いた手法があります。
レインボーテーブルとは予め一定量の文字列をハッシュ化したものを辞書化しておき、辞書と突合することにより瞬時に元のパスワードがわかるというものです。たとえば、下記のようなコマンドの結果をひたすら作りこんでおけば、password
やp@ssword
のようなパスワードは瞬時に破られてしまいます。
% echo -n 'password' | shasum -a 256
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 -
% echo -n 'p@ssword' | shasum -a 256
0fd205965ce169b5c023282bb5fa2e239b6716726db5defaa8ceff225be805dc -
これに対する有効な対策として、パスワードの文字列を長くすることにより、辞書に登録され得ない値を設定することが挙げられますが、我々人類の多くは怠惰であり、パスワードマネージャーを使うのもニュータイプに限られるため、システム側でなんとかしてやる必要があります。
それに対する一つの手段がSaltです。具体的にはユーザーに入力されたパスワードに何らかの文字列を追加してからハッシュ化し、保存してあげることにより、ユーザーに意識させることなく、パスワード暗号化を強固にすることが出来ます。
手軽にやるのであればユーザー名をハッシュ化したものをSaltとして利用してあげるのが良さそうです。
% echo -n 'pyama' | shasum -a 256
6b513449d1d9f85a652dc54f440603ec19761708c801eb8cd12fc96ee6cedbc9 -
% echo -n '6b513449d1d9f85a652dc54f440603ec19761708c801eb8cd12fc96ee6cedbc9password' | shasum -a 256
6ae3462c59be78ddf4f8071694a6c090d89da90220a12e8b5e912d17440e3fcd -
こうすることにより、レインボーテーブルの作成元となる文字列が6b513449d1d9f85a652dc54f440603ec19761708c801eb8cd12fc96ee6cedbc9password
の72文字となり、事前にレインボーテーブルを作成することが困難な状態を作ることが出来ます。
Stretchingを利用し、総当り攻撃にかかる時間を稼ぐ
Saltを利用することにより、事前にハッシュの計算結果を用意しておくことは困難になりますが、総当りで全ての文字列のハッシュ値を計算する場合、いつか必ずパスワードは破られてしまいます。この場合、総当りにかかる時間を増加させることしか有効な対策がないため、Steretchingを利用します。
Stretchingとはハッシュの計算を多重化することにより、単純に計算にかかる時間を増加させることを目的とします。
簡単なShellスクリプトを書いて検証してみましょう。test.sh
は文字列password
を引数で指定された回数+1回sha256ハッシュを計算します。
% cat test.sh
hash=`echo -n "password" | shasum -a 256`
for i in `seq 0 $1`
do
hash=`echo -n $hash | shasum -a 256`
done
echo $hash
- 1回 0.1秒
% time sh test.sh 1
7a55c84bff6647c28bd5367a810a6bfaf2320c95869474061bd9c7bc4e5c5012 -
sh test.sh 1 0.10s user 0.03s system 88% cpu 0.148 total
- 100回 3秒
% time sh test.sh 100
52fdf2c067d2c39367f35319377ada40c835115f0dc928de922e59ec5305b02c -
sh test.sh 100 2.97s user 0.89s system 92% cpu 4.163 total
- 1000回 30秒
% time sh test.sh 1000
5bbdcc1e453f6c315e577e941a6f34039e2821486002baec2b831f2d0e0d1f65 -
sh test.sh 1000 31.27s user 9.20s system 90% cpu 44.758 total
当たり前ですがこのようにStrethingを利用することで確実にハッシュの計算にかかる時間を増加させることができるので、総当り攻撃が成功するまでの時間を延長することが出来ます。今回は結果をわかりやすくするためにshasum
コマンドを利用しましたが、もっと高速に計算できるコマンドもあるため、Stretchingについてはシステムの負荷が許す限り回数を増やすことが良いでしょう。
STNS v0.1.0で対応しました
ここまでの話を踏まえ、STNS v0.1.0でSaltとStretching対応しております。
salt_enable
とstretching_number
のパラメーターでそれぞれの機能を有効化することが出来ます。さらにパスワード生成用のコマンドも準備しています。
こちらはOS Xで利用できるようにhomebrewを準備しています。
% brew tap stns/stns_passwd
% brew isntall stns_passwd
手元でSaltの有無、Streching回数を指定してパスワードハッシュを作成することが出来ます。
% stns-passwd --help
Usage of stns-passwd:
-c int
The number of times to stretching
-m string
Specifies the hash function(sha256/sha512) (default "sha256")
-s string
String used to salt. The SNS is the user name
-version
Print version information and quit.
% stns-passwd -s pyama -c 1000000 p@ssword
a3b20fc634ac4bad5be8a40566acb00adcd2e5bf2fb9be4750150553d529b799
まとめ
パスワードのDBへの保存の仕様は、新しく何かを作る時しか意外と調べることがなく、既存システム運用やってると全く触ることがない部分なので盲点で、自身はOSSを通じて学び直す機会があったの非常に良かったなと思いました。作ってるだけでフィードバック、学びがあるOSS最高だからみんなもっと作ったほうがいい。