해싱

Hashing

방법

원래 값을 되돌릴 수 없는 문자열로 바꿔 저장하는 방법으로, 비밀번호처럼 원본을 알 필요가 없는 값에 씁니다.

등장 배경

한때 서비스들은 사용자가 정한 비밀번호를 적힌 그대로 데이터베이스에 넣어 뒀습니다. 비밀번호를 잊었다고 문의하면 고객센터가 조회해서 알려 줄 수 있었고, 비밀번호 찾기 메일에 원래 비밀번호가 그대로 적혀 오기도 했습니다. 편리했고, 그래서 오래 갔습니다.

문제는 그 목록이 한 번 새 나갈 때 드러났습니다. 회원 열 명의 정보가 아니라 수백만 명의 아이디와 비밀번호가 짝지어진 채 통째로 넘어갔습니다. 게다가 사람들은 같은 비밀번호를 여러 서비스에 돌려 씁니다. 한 곳에서 새어 나온 목록으로 다른 서비스에 차례로 로그인을 시도하면 상당수가 열렸습니다. 털린 것은 한 회사인데 피해는 그 사람이 가입한 모든 곳으로 번졌습니다.

여기서 질문이 뒤집혔습니다. 어떻게 잘 지킬 것인가가 아니라, 새 나가더라도 쓸모없는 형태로 만들어 둘 수 있는가입니다. 서비스가 비밀번호를 확인하려고 원래 값을 알아야 할 이유가 사실 없다는 데서 답이 나왔습니다. 입력한 것이 전에 정한 것과 같은지만 알면 되고, 그 판정에는 원본이 필요하지 않습니다.

사용 절차

값을 한 방향으로만 뭉개는 함수에 넣어 나온 문자열을 저장하고, 나중에는 같은 함수를 다시 돌려 나온 값끼리 비교합니다. 같은 값을 넣으면 언제나 같은 문자열이 나오지만, 나온 문자열에서 원래 값으로 되돌아가는 길은 없습니다.

절차는 네 단계입니다.

  1. 저장할 때는 계정마다 무작위 값을 하나 만들어 비밀번호에 붙인 뒤 함수에 넣고, 나온 문자열과 그 무작위 값을 함께 저장합니다. 원본은 어디에도 남기지 않습니다.
  2. 확인할 때는 입력된 비밀번호에 저장해 둔 무작위 값을 붙여 같은 함수에 넣고, 결과가 저장된 문자열과 일치하는지 봅니다. 일치하면 통과입니다. 이 판정에 원본은 한 번도 쓰이지 않습니다.
  3. 함수는 일부러 느린 것을 고릅니다. bcrypt 나 Argon2 처럼 한 번 계산에 시간을 쓰도록 만든 함수들입니다. MD5 나 SHA-1 처럼 빠른 함수는 초당 수십억 번을 대입할 수 있어 짧은 비밀번호가 금방 맞아떨어집니다.
  4. 강도는 주기적으로 올립니다. 이런 함수에는 반복 횟수를 정하는 값이 있어 장비가 빨라진 만큼 올려 두고, 사용자가 로그인에 성공한 순간 새 설정으로 다시 계산해 갱신합니다.

1번의 무작위 값이 솔트입니다. 이것이 없으면 같은 비밀번호를 쓴 사람들의 저장값이 전부 똑같이 나옵니다. 흔한 비밀번호를 미리 계산해 둔 대조표 하나면 목록 전체를 한 번에 훑을 수 있고, 유출된 목록에서 같은 문자열이 만 번 반복되는 것만 봐도 그게 흔한 비밀번호라는 사실이 드러납니다. 계정마다 다른 솔트를 붙이면 같은 비밀번호라도 저장값이 달라져서, 공격하는 쪽은 계정 하나하나를 따로 상대해야 합니다.

적합한 상황과 한계

원래 값을 다시 읽을 일이 없는 자리에 맞습니다. 비밀번호가 대표적이고, 로그인 유지에 쓰는 토큰이나 다중 인증의 복구 코드처럼 대조만 하면 되는 값도 같습니다. 인증이 누구인지 확인하는 절차인데, 그 확인은 전부 대조로 끝나기 때문입니다.

대조 말고 두 가지 쓰임이 더 있습니다. 하나는 바뀌었는지 확인하는 일입니다. 파일의 해시값을 받아 두고 내려받은 파일을 같은 함수에 넣어 비교하면 한 글자라도 달라졌는지 알 수 있습니다. 다른 하나는 원본을 넘기지 않고 대조하는 일입니다. 두 회사가 겹치는 고객이 있는지 확인할 때 이메일 주소 대신 해시값 목록만 주고받는 식입니다.

한계는 세 가지입니다.

  1. 나중에 읽어야 하는 값에는 쓸 수 없습니다. 고객이 쓴 문서 본문이나 배송 주소는 다시 보여 줘야 하므로 암호화의 몫입니다.
  2. 값의 가짓수가 적으면 거의 소용이 없습니다. 휴대폰 번호는 후보가 유한해서 전부 넣어 보면 맞는 것이 나옵니다. 개인 식별 정보를 해싱했으니 개인을 알아볼 수 없게 됐다고 적는 문서가 자주 문제가 되는 이유입니다.
  3. 저장 구간만 지킵니다. 오가는 구간은 TLS가 맡습니다. 사용자가 입력한 비밀번호는 서버에 닿기 전까지 원본 그대로 움직이므로, 그 구간이 열려 있으면 저장을 아무리 잘해도 소용이 없습니다.

실무 용례

"비밀번호는 해싱해서 저장하니까 저희도 못 봅니다."

원본이 서버에 없어서 직원도 조회할 수 없다는 설명입니다.

"이거 MD5로 해싱돼 있는데요. 지금 기준으로는 그냥 둔 거나 마찬가지예요."

함수가 너무 빨라 대입으로 뚫린다는 지적입니다.

"이메일 해싱했다고 비식별이라고 쓰면 안 됩니다. 넣어 보면 맞아요."

후보가 적은 값이라 해싱해도 원래 값을 알아낼 수 있다는 경고입니다.

페이지덱이 첫 기업 고객의 보안 검토를 받던 때, 태오가 초기에 짜 둔 로그인 코드를 다시 열어 봤습니다. 비밀번호가 솔트 없이 SHA-256 한 번만 거쳐 저장돼 있었습니다. 새 나가지 않았으니 사고는 아니지만, 흔한 비밀번호를 쓴 계정은 목록이 넘어가는 순간 바로 열리는 상태였습니다.

옮기는 일이 까다로운 이유는 원본이 없다는 점 때문입니다. 저장된 값을 되돌려 새 함수에 다시 넣을 방법이 없습니다. 태오가 쓴 방법은 사용자가 다음에 로그인할 때를 기다리는 것이었습니다. 그 순간에는 원본이 잠깐 손에 들어오니, 옛 방식으로 대조해 통과시킨 뒤 곧바로 새 방식으로 다시 계산해 덮어썼습니다. 석 달 뒤 남아 있던 계정은 비밀번호를 다시 정하게 했습니다.

흔한 오해

해싱을 암호화의 한 종류로 보는 경우가 가장 많습니다. 둘 다 알아볼 수 없는 문자열이 나오니 같은 부류로 묶이기 쉽습니다. 하지만 암호화에는 열쇠가 있고 열쇠를 쥔 쪽은 원래 내용을 되돌려 읽습니다. 해싱에는 그런 열쇠가 없습니다. 이 차이를 놓치면 비밀번호를 암호화로 저장하는 설계가 나오는데, 열쇠를 쥔 서버가 털리면 비밀번호가 전부 평문으로 돌아옵니다.

해싱해 뒀으니 안전하다고 읽는 것도 흔합니다. 되돌릴 수 없다는 성질이 그 자체로 방어처럼 들리기 때문입니다. 실제로 공격하는 쪽은 되돌리려 하지 않고 후보를 넣어 봅니다. 흔한 비밀번호 목록을 차례로 함수에 넣어 저장값과 맞춰 보는 식이라, 함수가 빠르고 솔트가 없으면 몇 시간 만에 상당수가 열립니다. 되돌릴 수 없다는 말은 뒤집을 수 없다는 뜻이지 맞혀 볼 수 없다는 뜻이 아닙니다.

자주 헷갈리는 용어

용어되돌릴 수 있는가해싱과의 차이
암호화열쇠가 있으면 원래 내용으로 되돌아감나중에 읽어야 하는 값에 씁니다. 그래서 열쇠를 어디에 두고 누가 쥐는지가 설계의 중심이 되는데, 해싱에는 열쇠가 없어서 그 고민 자체가 없습니다

같이 보면 좋은 페이지

마지막 업데이트 2026-09-16