취약하거나 위험한 암호 알고리즘 사용 (MD5 비밀번호 해시)

Use of a Broken or Risky Cryptographic Algorithm

설명

이 취약점은 비밀번호를 저장하거나 검증할 때 MD5 같은 오래되거나 취약한 해시 알고리즘을 사용하는 경우 발생합니다. MD5는 설계가 오래되었고, 매우 빠르며, 충돌 공격과 무차별 대입(brute-force), 레인보우 테이블 공격에 취약합니다. 공격자는 유출된 해시 값만 가지고도 짧은 시간 안에 원래 비밀번호를 복구하거나, 같은 해시를 만드는 다른 비밀번호를 찾아 계정을 탈취할 수 있습니다.

잠재적 영향

  • 비밀번호 크래킹(비밀번호 탈취): 빠른 MD5 연산 속도를 이용하여 공격자가 대규모 무차별 대입 공격을 수행해 해시된 비밀번호를 실제 비밀번호로 복구할 수 있습니다.

  • 계정 탈취 및 권한 오남용: 탈취된 비밀번호를 이용해 사용자 계정에 로그인하고, 개인 정보 조회, 결제, 관리자 기능 수행 등 계정을 악용할 수 있습니다.

  • 재사용 비밀번호로 인한 2차 피해: 사용자가 다른 서비스에서도 같은 비밀번호를 사용하는 경우, 한 번 노출된 MD5 해시로 여러 시스템이 연쇄적으로 침해될 수 있습니다.

  • 규정 위반 및 법적 리스크: 안전하지 않은 비밀번호 저장 방식은 개인정보보호법, 컴플라이언스(예: GDPR 유사 규제) 요구사항을 위반해 과징금·제재 대상이 될 수 있습니다.

해결 방법

  • 비밀번호 전용 해시 함수 사용: bcrypt, scrypt, Argon2 같은 비밀번호 해시 알고리즘을 사용합니다. Go에서는 golang.org/x/crypto/bcrypt 패키지 사용을 권장합니다.

  • 느린 해시(연산 비용) 설정: bcrypt의 cost 값을 충분히 크게 설정해 무차별 대입 공격을 어렵게 합니다(예: 10 이상, 성능 테스트 후 결정).

  • 솔트(Salt) 자동 사용: bcrypt/Argon2는 내부적으로 솔트를 포함하므로, 별도의 수동 솔트 관리 대신 검증된 라이브러리를 그대로 사용합니다.

  • 기존 MD5 해시 마이그레이션: 로그인 시 MD5 해시를 검증한 뒤, 성공하면 즉시 bcrypt 등 안전한 해시로 재해시하여 저장하는 점진적 마이그레이션을 적용합니다.

  • 직접 구현 금지: 직접 해시·솔트·PBKDF 함수를 구현하지 말고, 검증된 라이브러리(bcrypt, Argon2 등)를 그대로 사용합니다.

취약한 코드 및 안전한 코드 예시

취약한 코드

안전한 코드

설명:

  • 취약한 코드: 위 비준수 코드에서는 사용자 비밀번호를 crypto/md5로 해시해 그대로 저장합니다. MD5는 매우 빠르게 계산되기 때문에 공격자가 GPU/ASIC 등을 사용해 초당 엄청난 양의 후보 비밀번호를 시도할 수 있어, 해시만 유출돼도 비밀번호를 쉽게 크래킹할 수 있습니다. 또한 솔트(salt) 사용도 없기 때문에, 같은 비밀번호는 항상 같은 해시를 만들어 레인보우 테이블 공격에 특히 취약합니다.

  • 안전한 코드: 준수 코드에서는 MD5 대신 비밀번호 전용 해시 알고리즘인 bcrypt를 사용합니다. bcrypt.GenerateFromPassword는 내부적으로 무작위 솔트를 포함해 느린 연산을 수행하므로 무차별 대입 공격의 비용을 크게 높입니다. bcrypt.CompareHashAndPassword를 통해, 저장된 해시와 입력 비밀번호를 안전하게 비교할 수 있습니다. 직접 솔트·반복 횟수를 구현하지 않고 검증된 라이브러리를 그대로 사용함으로써 MD5 사용으로 인한 취약점을 제거합니다.

참조

Last updated