TL;DR;
- パスワードは一般的な暗号化だけでなくSaltも加えた上でHash化するのが望ましい
- BCryptを使用すると暗号化データの中にSaltの情報が含まれるためSalt Columnが不要
- jBCrypt/BCrypt.java at master · jeremyh/jBCrypt · GitHub がJavaではおそらく安牌
パスワード暗号化
前提としてパスワードの保存について。 平文保存はまずめちゃくちゃまずいと思う、ネットワークに侵入されてDB見られたら終わってしまう。 暗号化で十分かというと実はそうでもない。内部に悪意のある管理者がいた場合DBにアクセスしてパスワードを復号するということもあり得る。 パスワードはシステムの最後の砦として、ユーザー本人以外が知り得ない状態にするのが望ましい。
そのために多くの場合Hash化を行うと思う。Hash化を行うことでパスワードの入力値 -> ハッシュ化パスワードの変換はでき、 ハッシュ化パスワードとDBに保存されたハッシュ化パスワードを比較し一致しているかどうか判断することができる。 しかし、ハッシュ化パスワードから元のパスワードを導き出すことはできないため、内部の悪意のある管理者によるパスワード取得を防ぐことができ、より堅牢にできる。 ただし、簡単なHash化関数だと元に戻すことができてしまうらしいし、Hash化の回数が少ないと脆弱性が増すということにも注意が必要らしい。
また、上記を行った上でもパスワードに対して辞書攻撃やレインボーテーブル攻撃をされてしまう可能性もある。 Saltをユーザーごとに設定し、パスワードにSaltを付与することでこの攻撃を防ぐことができる。
以上より、パスワード保存に当たっては以下が必要だと思う。
- 暗号化
- 適切なハッシュ化
- Saltの付与
BCrypt
Blowfish暗号化を実装したライブラリらしい。 多くの記事で推奨されているのと、社内のセキュリティに詳しいエンジニアがBlowfish暗号化を推奨していたので、 パスワードの暗号化ではBCryptを使用すれば恐らく大きな間違いはないと思う。
使い方は至って簡単。必須なメソッドは下記のようになる。
// saltを生成する。引数でHash化の回数が決まるらしい。 2の引数乗実行される。数を増やすと指数的に処理時間が増大するため注意 String gensalt(int log_rounds) // 平文のパスワードとsaltからハッシュ化されたパスワードを生成する String hashpw(String password, String salt) // 平文のパスワードとハッシュかれたパスワードを比較し一致しているかどうかを判定する // 引数にsaltが不要である点に注意 String checkpw(String plaintext, String hashed)
最後に
セキュリティ周りのことを書くのはドキドキします。 間違っている点があったらご指摘ください。