💻 프로그래밍

해시

Hash

데이터를 고정 길이 값으로 변환하는 함수. 해시 테이블, 암호화, 무결성 검증에 사용.

📖 상세 설명

해시(Hash)는 임의 크기의 데이터를 고정 크기의 값으로 변환하는 함수의 결과물입니다. 해시 함수는 동일한 입력에 항상 같은 출력을 생성하며, 출력에서 입력을 역산하기 어렵습니다(단방향성). 해시는 해시 테이블, 암호화, 데이터 무결성 검증, 블록체인 등에 광범위하게 사용됩니다.

해시 테이블(Hash Table)은 키-값 쌍을 저장하는 자료구조로, 해시 함수를 사용해 키를 배열 인덱스로 변환합니다. 이론적으로 O(1) 시간에 검색, 삽입, 삭제가 가능합니다. Python의 dict, JavaScript의 Object/Map, Java의 HashMap이 해시 테이블 기반입니다.

암호학적 해시 함수(SHA-256, SHA-3, bcrypt 등)는 보안에 특화되어 있습니다. 충돌 저항성(다른 입력이 같은 출력을 만들기 어려움), 역상 저항성(출력에서 입력 추측이 어려움)을 갖습니다. 비밀번호 저장, 디지털 서명, 블록체인에 사용됩니다.

해시 충돌(Collision)은 서로 다른 입력이 같은 해시 값을 만드는 현상입니다. 해시 테이블에서는 체이닝(Chaining)이나 개방 주소법(Open Addressing)으로 충돌을 처리합니다. 좋은 해시 함수는 충돌을 최소화하고 값을 균등하게 분포시킵니다.

💻 코드 예제

# Python 해시 예제

import hashlib
from collections import defaultdict

# 1. 기본 해시 함수
text = "Hello, World!"
hash_value = hash(text)
print(f"Python hash: {hash_value}")

# 2. SHA-256 해시
sha256_hash = hashlib.sha256(text.encode()).hexdigest()
print(f"SHA-256: {sha256_hash}")
# 출력: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

# 3. 파일 무결성 검증
def file_hash(filepath):
    sha256 = hashlib.sha256()
    with open(filepath, 'rb') as f:
        for chunk in iter(lambda: f.read(4096), b''):
            sha256.update(chunk)
    return sha256.hexdigest()

# 4. 해시 테이블 (dict) 활용
user_cache = {}
user_cache['alice'] = {'name': 'Alice', 'age': 30}
user_cache['bob'] = {'name': 'Bob', 'age': 25}
print(user_cache.get('alice'))  # O(1) 조회

# 5. 충돌 처리 예시 (체이닝)
class HashTable:
    def __init__(self, size=10):
        self.size = size
        self.table = [[] for _ in range(size)]

    def _hash(self, key):
        return hash(key) % self.size

    def set(self, key, value):
        index = self._hash(key)
        for i, (k, v) in enumerate(self.table[index]):
            if k == key:
                self.table[index][i] = (key, value)
                return
        self.table[index].append((key, value))

    def get(self, key):
        index = self._hash(key)
        for k, v in self.table[index]:
            if k == key:
                return v
        return None

🗣️ 실무 대화 예시

시니어: 비밀번호를 SHA-256으로 저장하고 있는데, bcrypt로 바꿔야 해요.

주니어: SHA-256이면 충분히 안전하지 않나요?

시니어: SHA-256은 빠른 해시라서 GPU로 초당 수십억 개를 시도할 수 있어요. bcrypt는 일부러 느리게 설계되어 브루트포스가 어렵습니다. 솔트도 자동으로 처리해줘요.

면접관: 해시 테이블의 시간 복잡도와 최악의 경우를 설명해주세요.

지원자: 평균적으로 O(1)이지만, 모든 키가 같은 버킷에 들어가면 O(n)이 됩니다. 이를 방지하려면 좋은 해시 함수와 적절한 로드 팩터 관리가 필요합니다. 보통 로드 팩터가 0.75를 넘으면 리사이징합니다.

면접관: 해시 충돌 해결 방법들을 비교해주세요.

지원자: 체이닝은 각 버킷에 연결 리스트를 두어 충돌을 처리하고, 구현이 간단합니다. 개방 주소법은 다른 빈 슬롯을 찾아 저장하며, 캐시 효율이 좋지만 삭제가 복잡합니다.

리뷰어: API 토큰을 MD5로 해싱하고 있는데, MD5는 더 이상 안전하지 않아요.

작성자: 충돌 공격이 가능하다고요?

리뷰어: 네, SHA-256이나 SHA-3로 교체하세요. 보안 관련 해시는 항상 최신 권장 알고리즘을 사용해야 합니다.

⚠️ 주의사항

🔗 관련 용어

📚 더 배우기