Skip to content

パスワードハッシュの自動マイグレーション機能の追加(Argon2id対応) #1306

@nanasess

Description

@nanasess

概要

現在、パスワードのハッシュアルゴリズムは SHA256-HMAC で固定されていますが、旧バージョン(2.11未満)との互換性のため SHA1 での認証もサポートしています。

しかし、ログイン成功後に古いアルゴリズムから新しいアルゴリズムへ自動的にマイグレーションする仕組みがありません。

また、現在推奨されている Argon2id などの最新アルゴリズムへの移行パスも提供したいです。

現状の実装

サポートされているアルゴリズム

アルゴリズム 条件 備考
HMAC-SHA256 AUTH_TYPE = 'HMAC' + salt あり 現在の標準
SHA1 AUTH_TYPE = 'HMAC' + salt なし 2.11未満互換
PLAIN AUTH_TYPE = 'PLAIN' 平文(テスト用)

認証フロー(SC_Utils::sfIsMatchHashPassword()

if (empty($salt)) {
    // 旧バージョン(2.11未満)からの移行:SHA1を使用
    $hash = sha1($pass.':'.AUTH_MAGIC);
} else {
    // 現在の方式:HMAC-SHA256を使用
    $hash = SC_Utils_Ex::sfGetHashString($pass, $salt);
}

課題

  • 旧アルゴリズム(SHA1)でログインが成功しても、新しいアルゴリズムへの更新処理がない
  • ユーザーがパスワードを変更するまで、古いハッシュのまま保存され続ける
  • Argon2id など、より安全な最新アルゴリズムへの移行パスがない

提案

Symfony Password Hasher の PasswordHasherInterface::needsRehash() のような仕組みを導入し、段階的なアルゴリズムマイグレーションを実現する。

マイグレーションパス

SHA1 (2.11未満) → HMAC-SHA256 (現在) → Argon2id (将来)

実装方針

1. アルゴリズム識別子の導入

ハッシュ値にアルゴリズム識別子を含める(PHP の password_hash() 形式に準拠):

# Argon2id の場合
$argon2id$v=19$m=65536,t=4,p=1$...

# HMAC-SHA256 の場合(既存データとの互換性のため、識別子なしも許容)
{sha256-hmac}ハッシュ値
または
ハッシュ値のみ(salt カラムで判別)

2. 設定による制御

// data/mtb_constants_init.php
define('PASSWORD_HASH_ALGOS', 'argon2id'); // 'sha256', 'argon2id', 'bcrypt'

3. 再ハッシュ判定と実行

// SC_Utils に追加
public static function sfNeedsRehash($hash, $salt)
{
    // Argon2id/bcrypt の場合は PHP 標準関数で判定
    if (password_get_info($hash)['algo'] !== null) {
        return password_needs_rehash($hash, PASSWORD_ARGON2ID);
    }
    
    // 旧アルゴリズム(SHA1, SHA256-HMAC)は再ハッシュ必要
    return true;
}

public static function sfGetHashString($str, $salt = null)
{
    if (PASSWORD_HASH_ALGOS === 'argon2id') {
        return password_hash($str, PASSWORD_ARGON2ID);
    } elseif (PASSWORD_HASH_ALGOS === 'bcrypt') {
        return password_hash($str, PASSWORD_BCRYPT);
    } else {
        // 既存の HMAC-SHA256
        return hash_hmac('sha256', $str.':'.AUTH_MAGIC, $salt);
    }
}

public static function sfIsMatchHashPassword($pass, $hashpass, $salt)
{
    // Argon2id/bcrypt の場合
    if (password_get_info($hashpass)['algo'] !== null) {
        return password_verify($pass, $hashpass);
    }
    
    // 既存のロジック(SHA1, SHA256-HMAC)
    // ...
}

4. ログイン時の自動マイグレーション

// SC_Customer::getCustomerDataFromEmailPass() などに追加
if (SC_Utils_Ex::sfIsMatchHashPassword($pass, $data['password'], $data['salt'])) {
    // 再ハッシュが必要か確認
    if (SC_Utils_Ex::sfNeedsRehash($data['password'], $data['salt'])) {
        $newHash = SC_Utils_Ex::sfGetHashString($pass);
        $objQuery->update('dtb_customer', 
            ['password' => $newHash, 'salt' => ''],  // Argon2id は salt 不要
            'customer_id = ?', 
            [$data['customer_id']]
        );
    }
    // ログイン成功処理...
}

メリット

  1. セキュリティ向上: 最新の Argon2id アルゴリズムを使用可能
  2. 透過的なマイグレーション: ユーザーは通常のログインだけで自動的に移行
  3. 後方互換性: 既存の SHA1/SHA256-HMAC ハッシュも引き続き認証可能
  4. 柔軟性: 設定で使用アルゴリズムを選択可能

対象ファイル

  • data/class/util/SC_Utils.php - ハッシュ化・検証・再ハッシュ判定メソッド
  • data/class/SC_Customer.php - 会員ログイン時の再ハッシュ処理
  • data/class/pages/admin/LC_Page_Admin_Index.php - 管理画面ログイン時の再ハッシュ処理
  • data/mtb_constants_init.php - アルゴリズム設定

参考

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions