弱い暗号アルゴリズムや危険な暗号方式の使用

弱い暗号アルゴリズムと安全でない暗号モード

説明

DES/3DES、RC2/RC4、IDEAなどの古い方式や弱いアルゴリズム、ECBなどの安全でないモード、MD5、SHA-1、SHA1withRSA、MD5withRSA などの弱いハッシュや署名は、機密性と完全性を損なうおそれがあります。ECBはブロックの繰り返しを露出させます。DESは鍵が短く総当たり攻撃に弱く、DES/3DESの64ビットブロックは、大量のデータでの衝突やSweet32攻撃の原因になります。MD5とSHA-1の衝突は署名や完全性の検証を破る可能性があります。また、高速な汎用ハッシュはパスワードの推測を容易にします。

想定される影響

  • パターンの露出、弱い鍵、暗号解析によるデータの漏えい
  • ハッシュの衝突を利用したファイル、トークン、更新プログラムの署名の偽造
  • MD5やSHA-1で保存したパスワードへの、レインボーテーブルやGPUを使った総当たり攻撃によるアカウント侵害
  • NISTやPCI DSSなど、適用される暗号要件への不適合

対処方法

  • 共通鍵暗号にはAES-128以上、可能であれば AES/GCM/NoPadding などの認証付き暗号を使用してください。署名には2048ビット以上の鍵を使う SHA256withRSA、またはP-256以上のECDSAを使用してください。
  • ECBは使用しないでください。GCM/CCMなどの認証付きモード、または適切なHMACを組み合わせたCBCなどで完全性も保護してください。
  • 暗号学的なハッシュや署名に使うMD5、SHA-1、SHA1withRSA、MD5withRSA を、SHA-256以上の方式に置き換えてください。
  • パスワードにはArgon2id、scrypt、bcrypt、PBKDF2などの専用方式を使い、十分な処理コストとソルトを設定してください。PBKDF2-HMAC-SHA256では600,000回以上を基準に、サーバー性能に合わせて調整してください。
  • ランダムなIV、Nonce、Saltは SecureRandom で生成し、必要に応じて getInstanceStrong を使用してください。同じ鍵でIVやNonceを再利用しないでください。
  • 鍵長、交換周期、安全な保管を管理し、必要に応じてKMSやHSMを利用してください。
  • コードや設定で利用可能なアルゴリズムを制限し、暗号ライブラリとプロバイダーを更新してください。

例

変更前

java
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.Signature;

public class LegacyCrypto {
    // Insecure: ECB exposes plaintext patterns
    public byte[] encryptEcb(byte[] plaintext, SecretKey key) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(plaintext);
    }

    // Insecure: MD5 is collision-prone and fast to brute-force
    public byte[] weakDigest(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        return md.digest(data);
    }

    // Insecure: SHA1-based signature is deprecated
    public byte[] signSha1(byte[] data, PrivateKey privKey) throws Exception {
        Signature sig = Signature.getInstance("SHA1withRSA");
        sig.initSign(privKey);
        sig.update(data);
        return sig.sign();
    }
}

変更後

java
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import java.nio.ByteBuffer;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.util.Base64;

public class ModernCrypto {
    // Secure: AES-GCM (AEAD) with random 96-bit nonce, 128-bit tag
    public byte[] encryptGcm(byte[] plaintext, SecretKey key) throws Exception {
        byte[] nonce = new byte[12];
        SecureRandom.getInstanceStrong().nextBytes(nonce);
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(128, nonce);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);
        byte[] ct = cipher.doFinal(plaintext);
        return ByteBuffer.allocate(nonce.length + ct.length).put(nonce).put(ct).array();
    }

    // Secure password hashing with PBKDF2 (salt + high iteration)
    public String hashPassword(char[] password) throws Exception {
        byte[] salt = new byte[16];
        SecureRandom.getInstanceStrong().nextBytes(salt);
        PBEKeySpec spec = new PBEKeySpec(password, salt, 600_000, 256);
        SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        byte[] hash = skf.generateSecret(spec).getEncoded();
        return Base64.getEncoder().encodeToString(salt) + ":" + Base64.getEncoder().encodeToString(hash);
    }

    // Strong signature with SHA-256
    public byte[] signStrong(byte[] data, PrivateKey privKey) throws Exception {
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initSign(privKey);
        sig.update(data);
        return sig.sign();
    }
}

解説:

  • 変更前: AES/ECBはブロックの繰り返しを露出させます。MD5は衝突に弱く、パスワード保存には計算が速すぎます。SHA1withRSA も衝突による署名偽造の危険があり、推奨されません。
  • 変更後: AES/GCMは認証付き暗号で、同じ鍵で再利用しないNonceと128ビットのタグを使い、改ざんを検証します。再送攻撃の防止には別途プロトコル側の制御が必要です。PBKDF2WithHmacSHA256 はソルトと多い反復回数により、パスワード推測のコストを高めます。SHA256withRSA は衝突に強いハッシュを署名に使用します。

参考資料