弱いハッシュによるパスワードの保存

計算コストが不足したパスワードハッシュ

説明

パスワードを平文で保存すると、保存先の侵害時にそのまま漏えいします。MD5、SHA-1、単純なSHA-256などの高速なハッシュでは、攻撃者が流出したハッシュに対して多数のパスワード候補を短時間で試せます。

想定される影響

許可されていないアクセス

復元されたパスワードを使われると、アカウントへの侵入、データの漏えい、なりすまし、不正取引などにつながるおそれがあります。

パスワードの使い回し

同じパスワードを他のサービスでも使っている場合、それらのアカウントも侵害される可能性があります。

法令や規制への不適合

パスワードの保護が不十分だと、適用されるデータ保護要件に反し、サービスへの信頼を損なう場合があります。

対処方法

  1. パスワード専用のハッシュ方式を使用してください。 平文では保存せず、新しいシステムではArgon2idを優先してください。既存のbcryptやPBKDF2にも十分な処理コストを設定し、サーバー性能に合わせて調整してください。
  2. パスワードごとに新しいランダムなソルトを使用してください。 計算済みの結果を複数のハッシュに使い回すことを防ぎます。ソルトはハッシュと一緒に保存できますが、パスワードの推測そのものは防げません。
  3. 必要な場合はFIPS-140要件を満たしてください。 検証済みの暗号モジュールでPBKDF2-HMAC-SHA256を使用し、600,000回以上を基準に処理コストを設定してください。アルゴリズム名だけで実装が認証されるわけではありません。

例

変更前

Spring Security 5.8形式のJDBC認証設定の抜粋です。クエリがユーザー名、パスワードハッシュ、有効状態を必要な順序で返すスキーマを前提とします。

java
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
  auth.jdbcAuthentication()
    .dataSource(dataSource)
    .usersByUsernameQuery("SELECT * FROM users WHERE username = ?")
    .passwordEncoder(new StandardPasswordEncoder()); // パスワード保存には弱いハッシュ
}

変更後

java
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
  auth.jdbcAuthentication()
    .dataSource(dataSource)
    .usersByUsernameQuery("SELECT * FROM users WHERE username = ?")
    .passwordEncoder(new BCryptPasswordEncoder()); // 計算コストを調整できるbcryptを使用
}

解説:

  • 変更前: 旧方式の StandardPasswordEncoder はSHA-256を1,024回繰り返します。ソルトがあっても、パスワード保存に十分な計算コストにはなりません。
  • 変更後: bcryptの処理コストを調整して推測を難しくします。パスワードの長さ制限と性能を確認し、既存のハッシュはログイン時の再ハッシュやパスワード再設定で移行してください。エンコーダーの交換だけでは、保存済みハッシュは変換されません。

参考資料