Hash
해시
데이터를 고정 길이 값으로 변환. 해시 테이블, 암호화, 무결성 검증.
해시
데이터를 고정 길이 값으로 변환. 해시 테이블, 암호화, 무결성 검증.
해시(Hash)는 임의의 크기의 데이터를 고정된 크기의 값으로 변환하는 함수입니다. 해시 함수는 동일한 입력에 대해 항상 동일한 출력을 반환하며, 입력이 조금만 달라져도 완전히 다른 출력이 생성됩니다. 이러한 특성 덕분에 데이터 무결성 검증, 빠른 데이터 검색, 암호화 등 다양한 분야에서 핵심적인 역할을 합니다.
해시 테이블(Hash Table)은 해시 함수를 활용한 대표적인 자료구조로, 키-값 쌍을 저장하고 평균 O(1) 시간 복잡도로 조회할 수 있습니다. Python의 dict, JavaScript의 Object, Java의 HashMap 등이 해시 테이블 기반으로 구현되어 있어, 대규모 데이터에서도 빠른 검색 성능을 제공합니다.
암호학적 해시 함수(SHA-256, MD5 등)는 단방향성이 핵심입니다. 해시 값으로부터 원본 데이터를 역산하는 것이 계산적으로 불가능하며, 비밀번호 저장, 디지털 서명, 블록체인 등에 사용됩니다. 특히 비밀번호는 해시로 저장하고 입력된 비밀번호의 해시와 비교하여 인증합니다.
해시 충돌(Collision)은 서로 다른 입력이 같은 해시 값을 생성하는 현상입니다. 좋은 해시 함수는 충돌 확률이 극히 낮지만, 해시 테이블에서는 체이닝(Chaining)이나 개방 주소법(Open Addressing)으로 충돌을 처리합니다. Git에서 커밋 ID가 SHA-1 해시인 것처럼, 파일 무결성 검증과 버전 관리에도 해시가 필수적입니다.
# 1. 해시 테이블 (Dictionary) 기본 사용
user_scores = {} # 빈 해시 테이블 생성
# O(1) 시간에 데이터 삽입
user_scores["alice"] = 95
user_scores["bob"] = 87
user_scores["charlie"] = 92
# O(1) 시간에 데이터 조회
print(user_scores["alice"]) # 출력: 95
# 키 존재 여부 확인 - O(1)
if "bob" in user_scores:
print(f"Bob의 점수: {user_scores['bob']}")
# 2. 암호학적 해시 (SHA-256)
import hashlib
def hash_password(password: str) -> str:
"""비밀번호를 SHA-256으로 해시하여 저장용 문자열 반환"""
salt = "my_secret_salt" # 실무에서는 랜덤 salt 사용
salted = password + salt
return hashlib.sha256(salted.encode()).hexdigest()
# 비밀번호 해시 생성
stored_hash = hash_password("mypassword123")
print(f"저장된 해시: {stored_hash[:32]}...")
# 로그인 시 검증
def verify_password(input_pw: str, stored: str) -> bool:
return hash_password(input_pw) == stored
print(verify_password("mypassword123", stored_hash)) # True
print(verify_password("wrongpassword", stored_hash)) # False
# 3. 파일 무결성 검증
def get_file_hash(filepath: str) -> str:
"""파일의 MD5 해시 계산 (무결성 검증용)"""
hash_md5 = hashlib.md5()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
# 4. 해시를 이용한 중복 제거
def remove_duplicates(items: list) -> list:
"""해시 기반 O(n) 중복 제거"""
seen = set() # set도 해시 테이블 기반
result = []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
return result
data = [1, 2, 2, 3, 3, 3, 4]
print(remove_duplicates(data)) # [1, 2, 3, 4]
"사용자 세션 조회가 느린 건 배열을 순회하고 있어서예요. 해시맵으로 바꾸면 O(n)에서 O(1)으로 개선됩니다. 세션 ID를 키로 사용하면 100만 사용자도 상수 시간에 조회할 수 있어요."
"해시 충돌은 체이닝과 개방 주소법으로 해결합니다. 체이닝은 같은 버킷에 연결 리스트로 저장하고, 개방 주소법은 다른 빈 버킷을 찾습니다. Python의 dict는 개방 주소법을 사용하며, 로드 팩터가 2/3를 넘으면 리사이징합니다."
"비밀번호를 MD5로 저장하면 안 됩니다. bcrypt나 argon2를 사용해주세요. MD5는 레인보우 테이블 공격에 취약하고, salt 없이 해시하면 같은 비밀번호가 같은 해시를 갖게 됩니다."
리스트 같은 가변 객체는 해시 키로 사용할 수 없습니다. 해시 값이 변경되면 조회가 불가능해지기 때문입니다. 튜플이나 frozenset처럼 불변 객체를 키로 사용하세요.
일반 해시는 빠르기 때문에 브루트포스 공격에 취약합니다. 비밀번호에는 bcrypt, scrypt, argon2처럼 의도적으로 느린 해시 알고리즘을 사용하고, 반드시 salt를 추가하세요.
용도에 맞는 해시를 선택하세요. 해시 테이블에는 빠른 해시(MurmurHash, xxHash), 암호화에는 SHA-256, 비밀번호에는 bcrypt/argon2를 사용합니다. Git은 SHA-1에서 SHA-256으로 전환 중입니다.