취약한 암호화 알고리즘 사용

Use of a Broken or Risky Cryptographic Algorithm

설명

DES/3DES, RC2/RC4, Blowfish 같은 오래된 암호나 AES-ECB 같은 부적절한 모드는 용도와 구성에 따라 기밀성이나 무결성을 약화할 수 있습니다. DES의 짧은 키, RC4의 알려진 약점, AES-ECB의 반복 블록 패턴 노출은 서로 다른 문제입니다. MD5와 SHA-1은 충돌 공격에 취약해 충돌 내성이 필요한 무결성 검사나 서명에 적합하지 않습니다.

잠재적 영향

  • 데이터 기밀성 훼손: DES/RC4 같은 약한 암호 또는 AES-ECB 사용으로 평문 패턴이 노출되거나 키가 추측되어 민감 정보가 유출될 수 있습니다.
  • 데이터 무결성 손상: MD5/SHA-1의 충돌 공격으로 파일 체크섬, 서명 검증 등의 무결성 보장이 무너질 수 있습니다.
  • 인증/권한 우회: 약한 해시/서명으로 토큰 위조나 메시지 인증 우회가 가능해 계정 탈취 등으로 이어질 수 있습니다.

해결 방법

  • 강력한 알고리즘 사용: 대칭키는 AES-GCM 또는 ChaCha20-Poly1305(인증된 암호), 해시는 SHA-256/384/512 또는 SHA-3를 사용하세요.
  • 금지 목록: DES/3DES, RC2/RC4, Blowfish, MD5, SHA-1, AES-ECB는 사용하지 마세요.
  • 안전한 모드/파라미터: AES는 GCM 권장(권장 96비트 무작위 IV). 같은 키로는 IV를 재사용하지 마세요. 키는 최소 128비트(권장 256비트).
  • 비밀번호 기반 키 파생: PBKDF2/Scrypt/Argon2로 키를 파생하고 충분한 반복/메모리 비용을 설정하세요.
  • 무결성 보장: 가능하면 AEAD(GCM/ChaCha20-Poly1305)를 사용하고, 불가 시 별도의 HMAC-SHA-256 등으로 인증하세요.
  • 검증된 라이브러리: Web Crypto API(node:crypto webcrypto)나 libsodium 같은 검증된 라이브러리를 사용하세요.

예시

변경 전

javascript
const crypto = require("crypto");

// 약한 암호 모드와 해시 사용 예시 (취약)
function encryptEcb(plaintext, key) {
  // BAD: AES-ECB는 패턴을 노출하고 무결성 보장이 없습니다
  const cipher = crypto.createCipheriv("aes-128-ecb", key, null);
  return Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
}

function md5Checksum(data) {
  // BAD: MD5는 충돌이 쉽고 무결성 검증에 부적합
  return crypto.createHash("md5").update(data).digest("hex");
}

// 데모용 고정 키(더 취약)
const key = Buffer.alloc(16, 0);
console.log(encryptEcb("secret text", key).toString("hex"));
console.log(md5Checksum("file-contents"));

변경 후

javascript
const crypto = require("crypto");

// 안전한 AES-256-GCM 사용 (기밀성 + 무결성 보장)
function encryptAesGcm(plaintext, key) {
  const iv = crypto.randomBytes(12); // 권장 96비트 IV
  const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
  const ciphertext = Buffer.concat([
    cipher.update(plaintext, "utf8"),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();
  return {
    iv: iv.toString("hex"),
    ct: ciphertext.toString("hex"),
    tag: tag.toString("hex"),
  };
}

function decryptAesGcm(enc, key) {
  const iv = Buffer.from(enc.iv, "hex");
  const ct = Buffer.from(enc.ct, "hex");
  const tag = Buffer.from(enc.tag, "hex");
  const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
  decipher.setAuthTag(tag);
  const plaintext = Buffer.concat([decipher.update(ct), decipher.final()]);
  return plaintext.toString("utf8");
}

// 강한 해시 사용 (무결성 체크)
function sha256Checksum(data) {
  return crypto.createHash("sha256").update(data).digest("hex");
}

// 필요 시 메시지 인증에 HMAC-SHA-256 사용
function hmacSha256(data, key) {
  return crypto.createHmac("sha256", key).update(data).digest("hex");
}

// 안전한 키 생성 (32바이트 = AES-256)
const key = crypto.randomBytes(32);
const enc = encryptAesGcm("secret text", key);
console.log(enc);
console.log("sha256:", sha256Checksum("file-contents"));
console.log("hmac:", hmacSha256("message", crypto.randomBytes(32)));

설명:

  • 변경 전:
    • AES-ECB는 동일 블록 입력에 동일 블록 출력이 나와 데이터 패턴이 노출됩니다. 무결성(위·변조 방지)도 제공하지 않습니다.
    • MD5는 알려진 충돌 공격이 가능해 파일 체크섬, 서명 검증 등에 사용할 경우 위조를 막지 못합니다.
    • 데모처럼 고정·약한 키를 사용할 경우 키 유출·추측 위험이 커집니다.
  • 변경 후:
    • AES-256-GCM은 인증된 암호(AEAD)로, 무작위 IV를 사용해 기밀성과 무결성을 함께 보장하며 태그로 위·변조를 탐지합니다.
    • SHA-256은 현대적이고 널리 검증된 해시로 충돌 내성이 강해 신뢰할 수 있는 기준 해시와 비교하는 무결성 검사에 적합합니다. 키 없는 해시만으로는 발신자를 인증하지 못합니다.
    • 키는 충분한 길이(32바이트)로 안전하게 생성하며, IV는 매번 새로 생성합니다. 무작위 값도 충돌 가능성이 있으므로 키당 사용량을 제한하고 재사용을 방지해야 합니다.

참조