해시 (Hash)

hi2li·2026년 6월 28일

security

목록 보기
11/12

개요

보안을 공부하다 보면 해시(Hash) 라는 용어를 매우 자주 접하게 된다.

비밀번호 저장, 파일 무결성 검증, 전자서명, Git, 블록체인 등 다양한 기술에서 해시가 사용되지만, 처음 접하는 사람들은 대부분 해시를 암호화의 한 종류라고 생각하는 경우가 많다.

실제로 인터넷에서도 "단방향 암호화"라는 표현을 쉽게 볼 수 있다. 하지만 엄밀히 말하면 해시는 암호화가 아니다.

암호화와 해시는 모두 데이터를 다른 형태로 변환한다는 공통점은 있지만, 목적과 동작 방식은 완전히 다르다.

  • 암호화는 데이터를 숨기는 것이 목적이고,
  • 해시는 데이터가 변하지 않았는지 확인하는 것이 목적이다.

이 차이를 이해하면 왜 비밀번호를 해시로 저장하는지, 왜 복호화가 필요 없는지, 그리고 Salt나 bcrypt 같은 기술이 왜 등장했는지도 자연스럽게 이해할 수 있다.

이번 글에서는 해시의 개념부터 특징, 그리고 암호화와의 차이까지 차근차근 알아보도록 하자.





1. 암호화와 해시는 무엇이 다를까?

해시를 이해하기 위해서는 먼저 암호화(Encryption) 와의 차이를 이해해야 한다.

둘 다 데이터를 다른 형태로 변환한다는 점에서는 비슷하지만, 목적이다.


암호화는 허가되지 않은 사람이 데이터를 읽지 못하도록 보호하는 것이 목적이다.

예를 들어 평문(Plaintext)인 비밀번호를 암호문(Ciphertext)으로 변환하면 제3자가 내용을 알아볼 수 없다.
또한 필요할 때 복호화키를 사용하여 언제든지 원래 데이터로 복원할 수 있다.



반면 해시는 "현재 데이터가 처음과 동일한가?" 를 확인하기 위해 사용하는 기술이다.

해시는 데이터를 일정한 길이의 해시값(Hash Value 또는 Digest) 으로 변환한다.

중요한 점은 변환된 해시값으로부터 원래 데이터를 복원할 수 없다는 것이다.

그래서 현대 암호학에서는 해시를 암호화의 한 종류로 분류하지 않는다.

과거에는 "단방향 암호화"라는 표현을 사용하기도 했지만, 현재는 보다 정확하게 단방향 함수(One-way Function) 또는 해시 함수(Hash Function) 라고 표현하는 것이 일반적이다.





2. 해시(Hash)란?

그렇다면 해시는 정확히 무엇일까?

해시는 임의의 길이를 가진 데이터를 일정한 길이의 값으로 변환하는 함수이다.

이를 수행하는 함수를 해시 함수(Hash Function) 라고 하며, 변환된 결과를 해시값(Hash Value) 또는 다이제스트(Digest)* 라고 부른다.

예를 들어 SHA-256 알고리즘을 사용하면 다음과 같이 변환된다.

hello

↓

SHA-256

↓

2cf24dba5fb0a30e26e83b2ac5...

입력 데이터는 한 글자일 수도 있고, 수백 GB의 파일일 수도 있다.

하지만 SHA-256은 입력 데이터의 크기와 관계없이 항상 256비트(32Byte) 길이의 해시값을 생성한다.

이처럼 해시는 데이터를 압축하거나 저장하기 위한 기술이 아니라,

데이터를 대표하는 고유한 지문(Fingerprint)을 만드는 기술

이라고 이해하면 쉽다.

사람의 지문으로 사람을 식별할 수 있듯이, 해시값도 원본 데이터를 대표하는 식별자 역할을 한다.



해시 함수의 특징

해시 함수는 일반적인 함수와는 조금 다른 성질을 가진다.

① 같은 입력은 항상 같은 출력이 나온다.

같은 데이터를 입력하면 언제 계산하더라도 항상 동일한 해시값이 생성된다.

100번, 1000번 계산해도 결과는 항상 동일하다.

이러한 성질 덕분에 파일이 변조되었는지 확인하거나 로그인 시 비밀번호를 검증할 수 있다.


② 입력이 조금만 달라도 결과는 완전히 달라진다.

해시는 입력 데이터가 아주 조금만 변경되어도 결과가 완전히 달라진다.

이를 Avalanche Effect(눈사태 효과) 라고 한다.

예를 들어.

"hello"와 "Hello" 는 대문자 하나만 다르지만 생성되는 해시값은 거의 모든 비트가 달라진다.

이러한 특성 덕분에 아주 작은 데이터 변경도 쉽게 탐지할 수 있다.

(※ 이 부분은 입력 문자열 한 글자가 바뀌었을 때 해시값이 완전히 달라지는 이미지를 함께 넣으면 이해하기 쉽다.)


③ 출력 길이는 항상 일정하다.

입력 데이터의 크기와 관계없이 출력 길이는 항상 동일하다.

예를 들어 SHA-256은

  • 문자 1개를 입력해도 256비트
  • 1MB 파일을 입력해도 256비트
  • 100GB 파일을 입력해도 256비트

길이의 해시값을 생성한다.

이것이 "임의의 길이의 입력을 고정된 길이의 출력으로 변환한다."라는 의미이다.


④ 원래 데이터로 복원할 수 없다.

해시는 단방향 함수(One-way Function) 이다.

즉,

원본 데이터

↓

해시 함수

↓

해시값

은 가능하지만,

해시값

↓

원본 데이터

는 현실적으로 불가능하다.

이 때문에 비밀번호를 저장할 때는 원본 비밀번호 대신 해시값만 저장하게 된다.


⑤ 충돌이 발생할 수 있다.

충돌(Collision)이란 서로 다른 두 개의 입력 데이터가 동일한 해시값을 생성하는 현상을 의미한다.

A ≠ B 이면서  Hash(A) = Hash(B)

해시 함수의 출력 길이는 고정되어 있기 때문에 이론적으로 충돌은 반드시 존재한다.

예를 들어 SHA-256은 항상 256비트만 출력하지만 입력 데이터는 사실상 무한히 많기 때문이다.

다만 좋은 해시 함수는 충돌을 찾는 것이 현실적으로 불가능할 정도로 어렵도록 설계되어 있다.

그래서 현재 널리 사용되는 SHA-256과 SHA-3 같은 알고리즘은 충돌을 찾기 매우 어려운 안전한 해시 함수로 평가받고 있다.










3. 해시는 어떻게 만들어질까?

앞에서 해시는 임의의 길이의 데이터를 고정된 길이의 해시값으로 변환하는 함수라고 설명했다.

그렇다면 해시 함수는 내부적으로 어떻게 이러한 해시값을 생성할까?


SHA-256을 비롯한 대부분의 해시 함수는 알고리즘마다 세부 구현은 다르지만, 전체적인 동작 흐름은 비슷하다.

먼저 입력된 데이터는 일정한 크기의 블록(Block) 단위로 나누어진다.

예를 들어 SHA-256은 데이터를 512비트(64Byte) 단위의 블록으로 분할하여 처리한다.

이후 각 블록은 여러 단계의 연산을 거치며 내부 상태(State)를 계속 변경하게 된다.

이 과정에서는 비트 회전(Rotate), XOR 연산, 덧셈(Modular Addition), 논리 연산 등이 반복적으로 수행되며, 이전 블록의 결과는 다음 블록 계산에도 영향을 미친다.

모든 블록의 처리가 끝나면 최종적으로 256비트의 해시값(Digest) 이 생성된다.

전체적인 흐름을 단순화하면 다음과 같다.

원본 데이터

↓

블록(Block) 단위 분할

↓

압축 함수(Compression Function) 반복 수행

↓

최종 해시값(Digest)

실제로는 훨씬 복잡한 수학적 연산이 수행되지만, 중요한 것은 다음 두 가지이다.

  • 입력 데이터가 조금만 달라져도 내부 연산 과정이 크게 달라진다.
  • 모든 블록이 서로 영향을 주기 때문에 작은 변경도 최종 해시값을 완전히 바꾸게 된다.

이것이 앞에서 설명한 Avalanche Effect(눈사태 효과) 가 발생하는 이유이다.


왜 복호화가 불가능할까?

많은 사람들이 해시값을 보면 "복호화하면 원래 데이터가 나오지 않을까?"라고 생각한다.

하지만 해시 함수는 애초에 복원할 수 있도록 설계된 함수가 아니다.

예를 들어 SHA-256은 어떤 입력이든 항상 256비트의 해시값만 생성한다.

"a"

↓

SHA-256

↓

256bit
100GB 파일

↓

SHA-256

↓

256bit

입력 데이터는 무한히 많지만 출력 가능한 해시값의 개수는 한정되어 있기 때문에, 하나의 해시값만 가지고 원래 데이터를 특정하는 것은 불가능하다.

그래서 해시는 데이터를 숨기는 기술이 아니라 데이터를 식별하는 기술이라고 이해하는 것이 더 정확하다.





4. 왜 비밀번호는 해시로 저장할까?

웹사이트는 사용자의 비밀번호를 다시 보여줄 일이 없다.

로그인 과정에서 필요한 것은 단 하나이다.

사용자가 지금 입력한 비밀번호가 회원가입 때 입력했던 비밀번호와 같은가?

즉, 원래 비밀번호를 복원할 필요가 없다.


만약 비밀번호를 평문으로 저장하면 데이터베이스(DB)가 유출되는 순간 모든 사용자의 비밀번호가 그대로 노출된다.

그렇다고 암호화해서 저장하는 것도 최선의 방법은 아니다.

암호화는 복호화를 위한 키(Key) 가 필요하므로, 서버가 침해되어 키까지 탈취되면 원래 비밀번호를 복원할 수 있기 때문이다.

그래서 대부분의 서비스는 복호화가 불가능한 해시(Hash) 를 이용해 비밀번호를 저장한다.

회원가입 시에는 비밀번호를 해시 함수에 입력하여 생성된 해시값만 데이터베이스에 저장한다.

비밀번호
    │
    ▼
 해시 함수
    │
    ▼
 해시값(DB 저장)

로그인할 때도 동일한 방식으로 입력한 비밀번호를 해시한 뒤, DB에 저장된 해시값과 비교한다.

해시값이 같다면 같은 비밀번호를 입력한 것이므로 로그인이 성공한다.

즉, 서버도 사용자의 원래 비밀번호는 알지 못하며, 해시값만 비교하여 인증을 수행한다.


그런데 SHA-256만 사용하면 안전할까?

아쉽게도 그렇지는 않다.

예를 들어 두 명의 사용자가 모두

password123

이라는 동일한 비밀번호를 사용한다면,

SHA-256의 특성상 생성되는 해시값도 완전히 동일하다.

password123

↓

SHA-256

↓

EF92B778...

이처럼 같은 입력은 항상 같은 출력이 생성되기 때문에, 공격자는 자주 사용되는 비밀번호의 해시값을 미리 계산해 둘 수 있다.

이렇게 미리 계산된 해시값 목록을 Rainbow Table(레인보우 테이블) 이라고 한다.

예를 들어 공격자는 다음과 같은 테이블을 미리 만들어 둘 수 있다.

비밀번호SHA-256
123456xxxx
passwordyyyy
password123zzzz
qwertyaaaa

데이터베이스에서 같은 해시값을 발견하면 원래 비밀번호를 매우 빠르게 추측할 수 있다.

즉, 해시 함수 자체를 역산하는 것이 아니라 미리 계산해 둔 결과를 찾아보는 방식이다.


Salt는 왜 필요할까?

이 문제를 해결하기 위해 등장한 것이 Salt이다.

Salt란 비밀번호에 추가하는 랜덤한 문자열을 의미한다.

회원가입 시 서버는 사용자마다 서로 다른 Salt를 생성한다.

그리고 비밀번호와 Salt를 함께 해시 함수에 입력한다.


password123 + 랜덤 Salt
            ↓ 

         SHA-256

            ↓

          해시값
<br>

이렇게 하면 같은 비밀번호를 사용하는 사용자라도 서로 다른 해시값이 생성된다.

따라서 Rainbow Table을 미리 만들어 두더라도 사용자마다 Salt가 다르므로 공격자는 기존 테이블을 사용할 수 없게 된다.


여기서 한 가지 오해하기 쉬운 점이 있다.

Salt는 비밀 정보가 아니다.

일반적으로 Salt는 해시값과 함께 데이터베이스에 저장된다.

공격자가 Salt를 알고 있더라도 사용자마다 새로운 해시를 다시 계산해야 하므로 공격 비용이 크게 증가한다.

즉, Salt의 목적은 비밀번호를 숨기는 것이 아니라 대규모 사전 계산 공격(Rainbow Table Attack)을 어렵게 만드는 것이다.










5. 현대 Password Hashing과 대표 알고리즘 비교

앞에서 살펴본 것처럼 Salt를 사용하면 Rainbow Table 공격을 효과적으로 방어할 수 있다.

하지만 오늘날에는 Salt만 사용하는 것으로는 충분하지 않다.

그 이유는 현대의 GPU와 전용 하드웨어는 SHA-256과 같은 일반 해시 함수를 초당 수십억 번 이상 계산할 수 있기 때문이다. 즉, Salt가 적용되어 있더라도 공격자가 무차별 대입(Brute Force)이나 사전 공격(Dictionary Attack)을 매우 빠르게 수행할 수 있다.

이러한 문제를 해결하기 위해 등장한 것이 Password Hashing 알고리즘이다.

Password Hashing 알고리즘은 일부러 연산 속도를 느리게 만들고, 많은 메모리를 사용하도록 설계되어 대량의 비밀번호 추측 공격을 어렵게 만든다.

현재 가장 많이 사용되는 알고리즘은 다음과 같다.

알고리즘특징권장 여부
MD5매우 빠르지만 충돌 공격 가능❌ 사용 금지
SHA-1충돌 공격 가능❌ 사용 권장하지 않음
SHA-256안전한 해시 함수이지만 비밀번호 저장용으로는 적합하지 않음
bcrypt연산 비용(Work Factor) 조절 가능
scrypt메모리 사용량을 크게 증가시켜 GPU 공격 방어
Argon2메모리와 연산량을 모두 조절 가능, 최신 표준✅ 권장

현재 대부분의 웹 서비스에서는 bcrypt 또는 Argon2를 사용하여 비밀번호를 저장하며, 단순히 SHA-256만 사용하는 방식은 권장되지 않는다.





6. 한 줄 정리

이번 글에서 살펴본 내용을 정리하면 다음과 같다.

  • 해시는 암호화가 아니라 무결성을 위한 단방향 함수이다.
  • 해시는 임의의 길이의 데이터를 고정된 길이의 해시값(Digest) 으로 변환한다.
  • 같은 입력은 항상 같은 해시값을 생성하고, 입력이 조금만 달라도 결과는 크게 달라진다.
  • 해시값만으로 원래 데이터를 복원하는 것은 현실적으로 불가능하다.
  • 비밀번호는 원본 대신 해시값을 저장하고 비교하는 방식으로 인증한다.
  • Salt는 동일한 비밀번호의 해시값을 다르게 만들어 Rainbow Table 공격을 방어한다.
  • 현대의 비밀번호 저장은 SHA-256보다 bcrypt, scrypt, Argon2와 같은 Password Hashing 알고리즘을 사용하는 것이 권장된다.

해시는 단순히 비밀번호 저장에만 사용되는 기술이 아니다. 파일의 무결성 검증, 전자서명, Git, 블록체인 등 다양한 분야에서 핵심적인 역할을 수행하며, 현대 정보보안의 가장 중요한 기반 기술 중 하나라고 할 수 있다.

profile
Easy come , Easy go

0개의 댓글