해시
고친 사람 github-actions[bot]
해시는 데이터 한 덩이를 대신하는 짧은 값입니다. 해시 함수에 데이터를 넣으면 나옵니다. 내용이 같으면 언제나 같은 값이 나오므로 내용이 바뀌었는지 확인하거나 내용을 가리키는 이름으로 씁니다. 같은 낱말의 다른 뜻은 맨 아래 절에서 가릅니다.
쉽고 빠른 이해
해시는 데이터의 지문 같은 짧은 값입니다. 몇 기가바이트짜리 파일도 수십 글자짜리 문자열 하나로 줄어듭니다.
긴 데이터를 통째로 비교하거나 주고받지 않아도 됩니다. 짧은 값끼리만 맞춰 보면 내용이 같은지 알 수 있습니다. 그 값을 이름처럼 불러 내용을 가리킬 수도 있습니다.
어떻게 쓰나:
- 데이터를 해시 함수에 넣어 값을 얻습니다
- 그 값을 데이터 옆에 적어 두거나 이름으로 씁니다
- 나중에 다시 계산해서 적어 둔 값과 맞춰 봅니다
대가도 있습니다. 서로 다른 데이터가 같은 값을 낼 수 있습니다. 그리고 값만 가지고는 원래 데이터를 되살리지 못합니다. 그래서 원래 데이터를 다시 꺼내야 하는 곳에는 해시를 쓰지 않습니다.
상세
이 절은 「해시값」이라는 뜻의 해시를 다룹니다. 먼저 이 값이 어디서 나오고 어떤 모양으로 적히는지 봅니다.
그다음 쓰임 둘을 봅니다. 하나는 내용이 바뀌었는지 확인하는 일입니다. 다른 하나는 내용으로 이름을 붙이는 일입니다.
지문에 빗대면
사람을 확인할 때 그 사람을 데려오지 않고 지문만 대조하기도 합니다. 지문은 작고, 같은 사람이면 늘 같습니다. 지문만 보고 그 사람의 얼굴을 그려 낼 수는 없습니다.
이 비유는 한 군데서 어긋납니다. 해시는 서로 다른 데이터끼리 겹칠 수 있습니다. 이 겹침은 아래 「같은 해시가 말해 주는 것」에서 다룹니다.
해시 함수가 내놓는 값
해시를 만드는 것은 해시 함수입니다. 해시 함수는 아무 길이의 데이터를 받아 길이가 정해진 값 하나를 내놓는 함수입니다. 그 값이 해시이고, 해시값이라고도 부릅니다.
해시 함수는 같은 입력에 언제 누가 계산해도 같은 값을 냅니다. 이 성질을 결정성이라고 부릅니다. 해시를 적어 두었다가 나중에 다시 계산해 맞춰 보는 쓰임은 모두 이 성질에 기댑니다.
보안 쪽 문서에서는 같은 값을 다이제스트라고 부르기도 합니다. 긴 글을 요약한 것이라는 뜻입니다. 해시와 다이제스트는 같은 것을 가리킵니다.
해시를 적는 모양
해시는 본래 바이트 몇십 개입니다. 사람이 읽고 옮겨 적기 좋게 대개 16진수 문자열로 적습니다. 바이트 하나가 16진수 두 글자가 됩니다.
그래서 출력 길이를 알면 글자 수가 정해집니다.
널리 쓰는 해시 함수 셋은 MD5 · SHA-1 · SHA-256 입니다. MD5 는 Message-Digest algorithm 5 의 줄임말입니다. SHA 는 Secure Hash Algorithm, 곧 안전한 해시 알고리즘의 줄임말입니다. 셋의 길이를 비교하면 이렇습니다.
SHA-256 이름 뒤의 256 이 출력 비트 수입니다.
입력을 한 글자만 바꿔 보면 해시가 어떻게 달라지는지 보입니다. 아래는 SHA-256 으로 계산한 값의 앞뒤 여덟 글자입니다.
sha256("hello") // 2cf24dba…938b9824
sha256("Hello") // 185f8db3…26381969
첫 글자의 대소문자만 다른데 값은 닮은 데가 없습니다. 비슷한 입력이 비슷한 해시를 내지 않도록 만든 것입니다. 그래서 해시만 보고는 입력이 얼마나 달랐는지 짐작할 수 없습니다.
내용이 바뀌었는지 확인하기
데이터가 만들어진 뒤로 한 비트도 안 바뀌었다는 성질을 무결성이라고 부릅니다. 해시는 무결성을 확인하는 가장 흔한 도구입니다. 데이터를 처음부터 끝까지 원본과 비교하는 대신 해시 둘만 비교합니다.
내려받는 파일이 대표적인 예입니다. 배포하는 쪽이 파일과 함께 그 파일의 해시를 적어 둡니다. 내려받은 사람은 자기 손에 들어온 파일로 해시를 다시 계산해 적힌 해시와 맞춰 봅니다.
sequenceDiagram
participant P as 배포하는 쪽
participant U as 사용자
P->>P: 파일의 해시를 계산한다
P->>U: 파일과 해시를 내준다
U->>U: 받은 파일로 해시를 다시 계산한다
alt 두 해시가 같다
Note over U: 파일을 그대로 쓴다
else 두 해시가 다르다
Note over U: 파일이 바뀌었다. 버리고 다시 받는다
end
전송 중에 바이트가 깨졌다면 다시 계산한 해시가 적힌 해시와 다르게 나옵니다. 저장해 둔 파일이 디스크에서 조금씩 상하는 경우도 같은 방법으로 잡습니다. 오래 보관하는 자료에 해시를 메타데이터로 붙여 두고 주기적으로 다시 계산하는 까닭입니다.
한계도 있습니다. 파일과 해시를 같은 곳에서 받으면 누군가 둘을 함께 바꿔치기할 수 있습니다. 해시는 「받은 파일이 적힌 해시와 맞나」만 알려 줍니다. 해시 자체를 믿을 수 있는지는 전자 서명 같은 다른 장치가 맡습니다.
체크섬과 가르기
체크섬도 데이터에서 짧은 값을 계산해 붙여 두는 방법입니다. 목적은 전송이나 저장 중에 우연히 생긴 오류를 잡는 것입니다. 그래서 계산이 빠르고 값이 짧습니다.
해시, 그중에서도 암호학적 해시 함수가 낸 해시는 한 걸음 더 갑니다. 누군가 일부러 데이터를 바꾸면서 해시를 그대로 맞추기가 현실적으로 불가능하게 만들었습니다. 우연한 오류만 걱정하면 체크섬으로 충분합니다. 속이려는 사람까지 걱정하면 암호학적 해시를 씁니다.
두 말이 섞여 쓰이기도 합니다. 파일 옆에 적힌 SHA-256 값을 「체크섬」이라고 부르는 경우가 흔합니다.
내용으로 이름 붙이기
보통 데이터의 이름은 사람이 정합니다. 파일 이름이나 데이터베이스의 번호가 그렇습니다. 해시를 쓰면 이름을 내용에서 계산해 낼 수 있습니다. 이런 방식을 내용 주소 지정이라고 부릅니다.
이름이 내용에서 나오면 두 가지가 저절로 따라옵니다. 같은 내용은 같은 이름을 얻으므로 한 번만 저장하면 됩니다. 내용이 한 글자라도 바뀌면 이름도 바뀌므로 이름이 같은 한 내용도 같습니다.
Git 이 이 방식으로 저장합니다. Git 은 파일 내용, 폴더 구조를 담은 트리, 커밋을 모두 자기 해시로 부릅니다.
커밋 안에는 해시 둘이 적힙니다. 하나는 그 시점의 폴더 구조를 담은 트리의 해시입니다. 다른 하나는 바로 앞 커밋의 해시이고, 이 바로 앞 커밋을 부모라고 부릅니다.
flowchart TD
C2["커밋 B · 이름은 해시"] -->|부모의 해시를 적음| C1["커밋 A · 이름은 해시"]
C2 -->|트리의 해시를 적음| T["트리 · 이름은 해시"]
T --> F1["파일 내용 · 이름은 해시"]
T --> F2["파일 내용 · 이름은 해시"]
그림에서 파일 하나가 바뀌면 그 파일의 해시가 바뀝니다. 그 해시를 적은 트리의 내용이 바뀌니 트리의 해시도 바뀝니다. 같은 이유로 커밋의 해시까지 바뀝니다.
그래서 커밋 해시 하나가 그 시점의 파일 전부와 앞선 기록 전부를 대신합니다. 지난 기록을 몰래 고치면 그 뒤 모든 커밋의 해시가 달라져 드러납니다. 이렇게 해시를 겹겹이 엮는 구조를 넓게 보면 머클 트리입니다.
긴 해시를 매번 다 적기는 번거롭습니다. 그래서 앞 몇 글자만 떼어 부르기도 합니다. 한 저장소 안에서 다른 해시와 겹치지 않을 만큼만 적으면 그것으로 대상을 찾을 수 있습니다.
같은 해시가 말해 주는 것
해시가 다르면 입력이 다른 것은 확실합니다. 같은 입력은 늘 같은 해시를 내기 때문입니다.
해시가 같을 때는 조심해야 합니다. 서로 다른 입력이 같은 해시를 내는 일을 해시 충돌이라고 부릅니다. 입력은 끝없이 많은데 출력은 길이가 정해져 있으니 충돌은 반드시 있습니다.
암호학적 해시 함수는 충돌이 있더라도 그 쌍을 찾아내기가 현실적으로 불가능하게 만듭니다. 그래서 이런 함수의 해시가 같으면 실무에서는 내용이 같다고 봅니다. 다만 MD5 와 SHA-1 은 충돌을 일부러 만드는 방법이 알려져 있습니다. 속이려는 사람을 막아야 하는 곳에는 이 둘의 해시를 믿지 않습니다.
해시테이블에 쓰는 해시는 사정이 다릅니다. 해시테이블은 키를 해시해서 값을 둘 칸을 고르는 자료구조입니다. 이런 용도의 해시 함수는 안전보다 속도를 챙겨 출력이 짧고 충돌이 흔합니다. 그래서 해시가 같으면 원래 키를 한 번 더 비교합니다.
해시로는 되돌리지 못한다
해시에서 원래 데이터를 되살리는 방법은 없습니다. 긴 입력을 짧은 값으로 줄이는 동안 정보가 버려지기 때문입니다. 할 수 있는 것은 후보를 하나씩 해시해 보고 값이 같은지 맞춰 보는 것뿐입니다.
이 성질 덕분에 서버는 비밀번호 대신 비밀번호의 해시를 저장합니다. 로그인 때 받은 비밀번호를 같은 방식으로 해시해 저장한 값과 비교합니다. 저장소가 털려도 공격자 손에 들어가는 것은 해시뿐입니다.
그래도 공격자는 위에서 본 방법을 쓸 수 있습니다. 흔한 비밀번호를 하나씩 해시해 훔친 값과 맞춰 보는 것입니다. 그래서 비밀번호용 해시는 한 번 계산하는 데 일부러 시간이 걸리게 만들어 맞춰 볼 수 있는 후보 수를 줄입니다. 이 방법은 비밀번호 해싱이 따로 다룹니다.
되돌릴 수 없다는 점이 암호화와 가르는 선입니다. 암호화는 키가 있으면 원래 데이터로 되돌리는 것이 목적입니다. 원문을 나중에 다시 꺼내야 하는 데이터라면 해시가 아니라 암호화를 씁니다.
해시라는 이름의 다른 쓰임
「해시」는 값 말고도 여러 뜻으로 불립니다. 대화나 문서에서 만나면 앞뒤를 보고 어느 뜻인지 가려야 합니다.
| 쓰임 | 가리키는 것 | 이렇게 나온다 |
|---|---|---|
| 동사로 | 데이터를 해시 함수에 넣어 값을 얻는 일. 해싱이라고도 부른다 | 「클라이언트 주소를 해시해서 서버를 고른다」 |
| 자료구조의 줄임 | 키로 값을 찾는 해시테이블 | 「이건 해시에 넣어 두자」 · Ruby 의 Hash |
| 인덱스 방식 | 해시테이블로 만든 데이터베이스 해시 인덱스. 같은 값 찾기는 빠르고 범위 검색은 못 한다 | 「이 열에 해시 인덱스를 걸자」 |
| 기호 | 문자 # |
해시태그 · 해시 기호 |
동사로 쓸 때도 뜻의 뿌리는 이 문서의 해시와 같습니다. 로드 밸런서가 요청에서 뽑은 값을 해시해 서버를 고르는 방식이 그렇습니다. 같은 값은 늘 같은 해시를 내므로 같은 클라이언트가 같은 서버로 갑니다.
관련 항목
해시를 만들어 내는 함수와 알고리즘
해시 함수 · 암호학적 해시 함수 · MD5 · SHA-1 · SHA-256 · SHA-3 · BLAKE2 · CRC
해시로 확인하는 성질과 장치
무결성 · 체크섬 · 결정성 · 전자 서명 · 메시지 인증 코드 · HMAC
해시를 이름으로 쓰는 저장 구조
내용 주소 지정 · Git · 커밋 · 오브젝트 · 머클 트리 · 중복 제거 · 블록체인
해시가 겹치거나 뚫리는 방식
해시 충돌 · 비둘기집 원리 · 생일 문제 · 충돌 저항성 · 역상 저항성 · 레인보우 테이블
해시로 비밀번호를 지키는 기법
비밀번호 해싱 · 솔트 · bcrypt · Argon2 · 암호화
해시와 이름이 겹치는 다른 개념
해시테이블 · 해시 인덱스 · 일관성 해싱 · 로드 밸런서 · 해시태그
해시를 기록해 쓰는 분야
다른 이름: hash · 해시값 · hash value · 다이제스트 · digest