💡 Key Takeaways
- What Hash Functions Actually Do (And Why You Should Care)
- MD5: The Broken Algorithm That Won't Die
- SHA-256: The Cryptographic Workhorse
- bcrypt: Purpose-Built for Password Security
나는 CEO에게 왜 우리의 전체 사용자 데이터베이스가 침해되었는지 설명해야 했던 날을 아직도 기억한다. 2016년, 나는 보안 엔지니어로 8년의 경력을 쌓았고 내가 무엇을 하고 있는지 알고 있다고 생각했다. 우리는 비밀번호를 해시하기 위해 MD5를 사용하고 있었는데—내가 합류하기 전 몇 년 전에 내려진 결정이었다—해커는 48시간도 지나지 않아 34만 개 사용자 비밀번호 중 87%를 파악했다. 이 보안 사고는 우리에게 230만 달러의 수정 비용과 수많은 엔지니어링 시간을 소모하게 했으며, 우리의 명성을 거의 파괴할 뻔했다. 이 아픈 교훈은 나에게 결정적인 것을 가르쳐주었다: 해시 함수에 대한 이해는 더 이상 개발자에게 선택 사항이 아니다. 이것은 기본이다.
💡 주요 내용
- 해시 함수가 실제로 하는 일 (그리고 왜 신경 써야 하는지)
- MD5: 죽지 않는 부서진 알고리즘
- SHA-256: 암호학적 작업 말
- bcrypt: 비밀번호 보안을 위해 설계됨
오늘날, 15년 경력의 선임 보안 아키텍트로서, 나는 수백 개의 코드베이스를 검토하고 수십 개의 스타트업과 상담해왔다. 같은 실수가 계속 나타난다. 개발자들은 해시 함수를 서로 바꿔 사용할 수 있는 블랙 박스로 여기며, "빠르기" 때문에 MD5를 선택하거나 보안이 확실해 보인다는 이유로 SHA-256을 선택한다. 그러나 진실은 이렇다: 잘못된 해시 함수를 선택하는 것은 잠수함에 방충망을 설치하는 것과 같다. 보안처럼 보일 수 있지만 압력이 가해질 때 당신을 구할 수는 없다.
해시 함수가 실제로 하는 일 (그리고 왜 신경 써야 하는지)
기본부터 시작해 보자. 해시 함수는 크기에 상관없이 입력을 받아 고정 크기의 출력, 즉 해시 또는 다이제스트를 생성한다. 마치 수학적 지문이라고 생각하면 된다. "password123"을 입력하면 "482c811da5d5b4bc6d497ffa98491e38"와 같은 결과가 나온다. 동일한 입력은 항상 동일한 출력을 생성하지만, 아주 작은 변화—예를 들어 "password124"—는 완전히 다른 해시를 만든다.
이 결정론적 행동 덕분에 해시 함수는 믿을 수 없을 만큼 유용하다. 나는 데이터 무결성 검사, 디지털 서명, 비밀번호 저장 및 캐시 키를 위해 매일 그것들을 사용한다. 그러나 대부분의 개발자들이 놓치고 있는 것은: 모든 해시 함수가 동일하게 만들어진 것은 아니며, 잘못된 것을 사용하면 치명적일 수 있다.
해시 함수에는 세 가지 중요한 속성이 있다. 첫째, 이들은 단방향 함수이다—원래 입력으로 돌아갈 수 없다. 둘째, 충돌 저항성이 있어야 하며, 동일한 해시를 생성하는 두 개의 다른 입력을 찾는 것은 계산적으로 불가능해야 한다. 셋째, 입력의 작은 변화가 극적으로 다른 출력을 생성하는 눈사태 효과를 나타낸다.
내 상담 작업에서, 나는 개발자들이 해시 함수를 암호화와 혼동하는 것을 많이 보았다. 이는 위험하다. 암호화는 올바른 키로 되돌릴 수 있지만, 해싱은 그렇지 않다. 데이터를 암호화할 때는 나중에 복호화할 계획을 세운다. 데이터를 해싱할 때는 단방향 변환을 만드는 것이다. 나는 한 번 AES를 사용하여 비밀번호를 "암호화"하고 키를 동일한 데이터베이스에 저장하는 의료 스타트업을 감사한 적이 있다. 그들은 자신들이 안전하다고 생각했다. 그들은 안전하지 않았다.
실제 세계의 영향은 막대하다. 2023 Verizon 데이터 유출 조사 보고서에 따르면, 86%의 유출이 도난당한 자격 증명과 관련이 있다. 비밀번호를 잘못 저장하고 있다면, 당신은 사용자를 위험에 빠뜨리는 것뿐만 아니라, 당신의 전체 비즈니스도 위험에 빠뜨리는 것이다. 나는 적절한 해시 처리가 있었더라면 보안 사건으로 부도가 난 회사를 몇 개 보아왔다.
MD5: 죽지 않는 부서진 알고리즘
MD5 (Message Digest Algorithm 5)는 1991년 Ronald Rivest에 의해 설계되었다. 128비트 해시 값을 생성하며, 일반적으로 32글자 16진수 숫자로 표현된다. 10년 이상 동안 비밀번호 저장에서 파일 무결성 검사까지 모든 것을 위한 주요 해시 함수였다. 그러다가 우리는 그것이 근본적으로 잘못되었다는 것을 발견했다.
"MD5와 bcrypt의 차이는 기술적인 것만이 아니다—수백만 달러가 드는 유출과 단순히 불편한 유출의 차이다. 당신의 해시 함수를 선택할 때 마치 당신의 회사의 생존이 그에 달려 있는 것처럼 선택하라, 왜냐하면 정말로 그렇기 때문이다."
MD5에 대한 최초의 충돌 공격은 2004년에 Xiaoyun Wang과 그녀의 팀에 의해 발표되었다. 그들은 두 개의 다른 입력이 단 몇 시간의 계산으로 동일한 MD5 해시를 생성할 수 있음을 입증했다. 2012년까지 연구자들은 소비자 하드웨어에서 몇 초 만에 MD5 충돌을 생성할 수 있었다. 오늘날 클라우드 컴퓨팅을 통해 약 0.65달러의 AWS 컴퓨팅 시간으로 충돌을 생성할 수 있다.
나는 여전히 생산 시스템에서 정기적으로 MD5를 마주한다. 지난달, 나는 매월 5천만 달러의 거래를 처리하는 핀테크 애플리케이션을 검토했다. 그들은 API 토큰을 해시하는 데 MD5를 사용하고 있었다. 내가 그 취약점을 지적했을 때, 주요 개발자는 "하지만 우리는 체크섬을 위해서만 사용하고, 비밀번호에는 사용하지 않는다"라고 말했다. 이는 본질적으로 문제를 간과하는 것이다. MD5의 충돌 취약성은 그것을 어떤 보안이 중요한 애플리케이션에도 맞지 않게 만든다.
위험의 구체적인 예는 다음과 같다. 공격자는 동일한 MD5 해시를 가진 두 개의 서로 다른 실행 파일을 생성할 수 있다. 그들은 무해한 버전을 코드 검토를 위해 제출하고, 승인을 받은 후 악성 버전으로 바꾼다. 당신의 MD5 체크섬 검증은 통과하지만, 당신은 악성코드를 배포한 것이다. 이것은 이론적인 것이 아니다—실제 공격에서도 발생했으며, MD5 충돌을 이용한 Flame 악성코드가 Microsoft의 코드 서명에서 그 예이다.
한때 MD5를 매력적으로 만든 속도는 이제 가장 큰 약점이 되었다. 현대 하드웨어에서는 단일 GPU를 사용하여 초당 약 80억 개의 MD5 해시를 계산할 수 있다. 이로 인해 무차별 공격이 매우 용이해졌다. 나는 NVIDIA RTX 4090이 장착된 내 워크스테이션에서 테스트를 실행했다: 10만 개의 MD5 해시된 비밀번호가 있는 데이터베이스를 47분 만에 해독했다. 비밀번호는 약하게 설정된 것이 아니었다—대문자, 소문자 및 숫자를 혼합하여 평균 10자였다. MD5는 현대 컴퓨팅 파워에 대해 방어할 수 없다.
그럼에도 불구하고 MD5는 여전히 존재한다. 나는 레거시 시스템, 임시방편적인 스크립트 및 2010년 이후 업데이트되지 않은 튜토리얼에서 그것을 본다. 개발자들은 빠르기 때문에, 익숙하기 때문에, "중요한 것을 저장하고 있지 않으니"라는 이유로 선택한다. 그러나 보안은 그렇게 작동하지 않는다. 대부분 안전할 수는 없다. 당신의 해시 함수가 암호학적으로 타당하거나, 아니면 터질 준비가 된 책임이다.
SHA-256: 암호학적 작업 말
SHA-256은 SHA-2 계열의 일부로, NSA에 의해 설계되고 2001년에 발표되었다. 256비트 해시 값을 생성하며, 일반적으로 64글자 16진수 문자열로 표현된다. MD5와 달리 SHA-256은 여전히 암호학적으로 안전하다. 실질적인 충돌 공격이 없으며, 비트코인의 작업 증명 알고리즘을 포함한 현대 보안 인프라의 중추이다.
| 해시 함수 | 속도 | 사용 사례 | 보안 상태 |
|---|---|---|---|
| MD5 | 매우 빠름 (~300 MB/s) | 체크섬, 비보안 애플리케이션 | 암호학적으로 손상됨 - 비밀번호에 사용하지 말 것 |
| SHA-256 | 매우 빠름 (~150 MB/s) | 디지털 서명, 인증서, 파일 무결성 | 무결성에 안전하고, 비밀번호에는 잘못된 도구 |
| bcrypt | 고의로 느림 (조정 가능) | 비밀번호 해싱 | 업계 표준 - 비밀번호를 위해 설계됨 |
| Argon2 | 고의로 느림 (조정 가능) | 비밀번호 해싱, 키 파생 | 현대 표준 - 비밀번호 해싱 대회 우승자 |
| PBKDF2 | 구성 가능한 느림 | 비밀번호 해싱, 레거시 시스템 | 허용 가능하지만 bcrypt/Argon2 선호됨 |
나는 SHA-256을 광범위하게 사용하지만, 중요한 경고가 있다. 데이터 무결성, 디지털 서명 및 블록체인 애플리케이션에 대해 훌륭하다. 빠르다—내 노트북은 초당 약 5억 개의 SHA-256 해시를 계산할 수 있으며, 이것은 파일 다운로드를 확인하거나 콘텐츠 주소 지정 저장 시스템을 만드는 데 적합하다. Git은 정확히 이런 목적으로 SHA-1( SHA-256의 이전 버전)을 사용한다.
하지만 개발자들이 잘못 사용하는 지점은 다음과 같다: 비밀번호 해싱에 SHA-256을 사용한다. 이는 논리적으로 보일 수 있다—안전하고, 빠르며, 보안 표준에서 권장되기 때문이다. 문제는 "빠름"이라는 것이 비밀번호 해싱에 대해 원하는 것이 아니란 것이다. 그 5억 개의 해시를 초당 기억하라. 이는 적절한 GPU를 가진 공격자가 초당 5억 개의 비밀번호 추측을 시도할 수 있음을 의미한다.
실제 숫자로 설명하겠다. 나는 최근에 네 개의 RTX 4090 GPU가 장착된 시스템에서 hashcat을 사용하여 SHA-256 해시에 대한 비밀번호 크래킹을 테스트했다. 이 설정은 약 8,000달러에 달하며 초당 2000억 개의 SHA-256 해시를 계산할 수 있었다. 그렇게 한다면, 대문자, 소문자 및 숫자를 포함한 8자 비밀번호의 전체 공간을 약 3.5시간 만에 소진할 수 있었다. 소금(salt)을 사용한다고 해도—항상 사용해야 한다—SHA-256의 속도는 무차별 공격을 극도로 효과적으로 만든다.
SHA-256의 적절한 사용 사례는 암호학적 보안이 필요하지만 비밀번호 저장이 필요 없는 경우이다. 나는 메시지가 손상되지 않았음을 확인하기 위해 HMAC(해시 기반 메시지 인증 코드) 구현에 사용할 때, 또는 콘텐츠에서 결정론적 ID를 생성할 때 사용한다. 인증서 체인 및 디지털 서명에서도 사용한다. 이 애플리케이션들은 SHA-256의 속도와 보안으로부터 혜택을 본다.
내가 추천하는 한 가지 패턴은 SHA-256을 키 파생 함수의 일부로 사용하는 것이지만, 절대 단독으로 사용하지 않는 것이다. 예를 들어 최근 프로젝트에서, 우리는 사용자 비밀번호로부터 암호화 키를 생성할 필요가 있었다. 우리는 SHA-256를 기본 해시 함수로 사용하여 PBKDF2를 사용했다.