해싱 vs 암호화 vs 인코딩: 무엇이 다른가
해싱·암호화·인코딩은 서로 바꿔 써도 될 것처럼 들리고 늘 혼동되지만, 완전히 다른 세 가지 문제를 풉니다. 이를 혼동하면 실제 보안 버그로 이어집니다 — 해시해야 할 비밀번호를 '암호화'한다거나, Base64를 비밀인 것처럼 다루는 식으로요. 이 가이드는 그 경계를 분명히 그어, 늘 올바른 것을 집어 들 수 있게 합니다.
인코딩: 데이터를 안전하게 운반하기
인코딩은 특정한 형태를 기대하는 시스템을 통과할 수 있도록 데이터를 다른 형식으로 변환합니다. Base64, URL 퍼센트 인코딩, HTML 엔티티가 모두 인코딩입니다. 키도 비밀도 없습니다: 누구나 인코딩을 되돌릴 수 있으며, 바로 그것이 핵심입니다 — 받는 쪽이 디코딩해야 하니까요.
목표가 비밀이 아니라 호환성일 때 인코딩을 씁니다: 이진 데이터를 JSON 필드에 넣거나, 값을 URL에 안전하게 싣거나, 이미지를 data: URI로 임베드할 때요. 인코딩을 데이터를 '보호'하는 것으로 생각한다면, 그게 바로 잘못된 도구를 집었다는 경고 신호입니다.
암호화: 비밀로 유지하되 복원 가능하게
암호화는 키로 데이터를 뒤섞어, 올바른 키를 가진 사람만 원본으로 되돌릴 수 있게 합니다. 설계상 양방향입니다 — 키로 암호화하고, 키(또는 그 쌍)로 복호화합니다. 보안은 알고리즘을 숨기는 게 아니라 전적으로 키를 비밀로 유지하는 데 달려 있습니다.
나중에 다시 읽어야 하는 비밀스러운 무언가를 저장·전송해야 할 때 암호화를 씁니다: 전송 중인 메시지(HTTPS), 저장된 파일, 민감한 개인정보를 담은 데이터베이스 열 등이요. 핵심 특성은 복원 가능성입니다: 설계상, 키를 가진 사람은 원본을 되찾을 수 있습니다.
해싱: 단방향 지문
해싱은 데이터를 단방향 함수에 통과시켜 고정 길이 다이제스트를 만듭니다. 같은 입력은 항상 같은 해시를 내지만, 키도 없고 되돌릴 방법도 없습니다 — 출력에서 입력을 유도할 수 없습니다. 좋은 암호학적 해시는 같은 다이제스트를 갖는 두 입력을 찾는 것도 사실상 불가능하게 만듭니다.
복원이 아니라 검증을 위해 해싱을 씁니다: 다운로드가 변조되지 않았는지 확인하거나, 두 파일을 비교하거나, 콘텐츠 중복을 제거할 때요. 되돌릴 수 없기에, 원본을 다시 가질 필요가 전혀 없고 단지 무언가와 일치하는지만 확인하면 될 때 해싱이 바로 정답입니다.
이 셋을 묶어 주는 비밀번호 예시
비밀번호는 이 셋이 충돌하고 실수가 가장 치명적인 지점입니다. 저장된 비밀번호는 절대 암호화하면 안 됩니다. 암호화는 가역적이라, 키를 훔친 사람이 모든 비밀번호를 손에 넣기 때문입니다. 대신 해시하여, 유출되어도 비밀번호 자체가 아니라 다이제스트만 드러나게 합니다.
하지만 단순한 SHA-256 해시는 너무 빠릅니다: 공격자가 초당 수십억 번 추측할 수 있습니다. 그래서 비밀번호 해싱은 bcrypt, scrypt, Argon2처럼 의도적으로 느리고 솔트를 더한 알고리즘을 씁니다. 솔트는 동일한 비밀번호가 다르게 해시되게 하고, 느림은 대량 추측을 비싸게 만듭니다. 여기서 인코딩은 전혀 역할이 없습니다.
빠른 의사결정 가이드
무엇이 필요한지 확신이 서지 않을 땐, 달성하려는 바를 묻고 그에 맞춰 고르세요.
- 데이터를 전송·저장하고 나중에 정확한 값을 비공개로 다시 읽어야 하나요? 암호화.
- 데이터가 일치하는지만 확인하고 복원할 필요는 없나요? 해싱 — 비밀번호라면 느리고 솔트를 더한 해시(bcrypt/Argon2).
- 텍스트 전용 또는 URL 전용 통로로 데이터를 온전히 옮겨야 하나요? 인코딩(Base64, URL 인코딩) — 비밀 목적엔 절대 아님.
- 메시지가 공유 키를 가진 사람에게서 왔음을 증명해야 하나요? 해시와 비밀 키를 결합한 HMAC.