Web屋のネタ帳( http://neta.ywcafe.net/ )様の
これからの「パスワード」の話をしよう( http://neta.ywcafe.net/001184.html )で
紹介されているパスワードのハッシュ化のバグについて突っ込んでみる
「1回ハッシュ化を解読できただけ、プレーンパスワードを入手することが可能である」
というものである。
問題の部分はここ
/** * 平文のパスワードをハッシュ&stretchするメソッドです。 * loop回数は1000としていますが、999でも1001でもお好みでどうぞ。 * ただしループ回数は処理時間に直結しますのでほどほどの数値で。 */ private static final String hashAndStretch(String plainPasswd, String salt) { int loop = 1000; String hashedPasswd = ""; for (int i = 0; i < loop; i++) { hashedPasswd = DigestUtils.sha256Hex(hashedPasswd + plainPasswd + salt); } return hashedPasswd; }
<凡例>
ソルト:SSSSSSSS
<トレース>
XXXXXXXX ← DigestUtils.sha256Hex("YYYYYYYY" + "PASSWORD" + "SSSSSSSS")
クラッカーがXXXXXXXXXのハッシュ値を解析し、元の文字列が「YYYYYYYYPASSWORDSSSSSSSS"」と判明したとする。
この時点で元文字列の中にプレーンパスワードが含まれていることになる。
また、ハッシュ化された文字列には「0123456789abcdef」の文字しか含まれておらず、
「それ以外の文字が含まれていた場合容易にプレーンパスワードではないか」
一般的なパスワードには少なからず「0123456789abcdef」以外の文字が含まれているだろうし、
上記のことをふまえてプログラムを修正すると。。
/** * 平文のパスワードをハッシュ&stretchするメソッドです。 * loop回数は1000としていますが、999でも1001でもお好みでどうぞ。 * ただしループ回数は処理時間に直結しますのでほどほどの数値で。 */ private static final String hashAndStretch(String plainPasswd, String salt) { int loop = 1000; String hashedPasswd = DigestUtils.sha256Hex(plainPasswd + salt);; for (int i = 0; i < loop; i++) { hashedPasswd = DigestUtils.sha256Hex(hashedPasswd + DigestUtils.sha256Hex(salt + i)); } return hashedPasswd; }
hashed = hash(hashed + salt + i) で十分やと思う