2011-05-19

「これからの「パスワード」の話をしよう」のバグについて突っ込む

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;
    }

ここのロジックトレースしてみると

凡例

プレーンパスワードPASSWORD

ソルト:SSSSSSSS

トレース

最終的なハッシュパスワードが「XXXXXXXX」とする

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;
    }

プレーンパスワードループの外でハッシュ化し、

またソルトを毎回違う値にハッシュ変換することにより

元の文字列の推測を行いにくく修正した

記事への反応(ブックマークコメント)

ログイン ユーザー登録
ようこそ ゲスト さん