[Python] Salt
앞서 해시와 SHA-256에 대해 포스팅을 한적이 있었다.
[알고리즘] SHA-256 해시 알고리즘: 개념과 활용
[알고리즘] SHA-256 해시 알고리즘: 개념과 활용SHA-256(Secure Hash Algorithm 256)은 SHA-2 계열의 암호학적 해시 함수 중 하나로,입력된 데이터를 256비트(32바이트)의 고정된 길이 해시 값으로 변환하는 알
heywantodo.tistory.com
해당 포스팅에서 사용자의 비밀번호와 같은 민감한 데이터를 저장할때는 단순 해싱만으로 충분하지 않고,
Salt 기법을 함께 사용해야지 보안성을 높일 수 있다고 짤막하게 언급했었다.
이번 포스팅에서는 Salt에 대해 보다 자세히 알아보고자 한다.
Salt란?
Salt는 암호화(특히 해싱)할 때 추가하는 랜덤한 값이다. 주로 비밀번호를 해싱할 때 사용되며, 해시된 값이 예측 불가능하도록 만들어 보안을 강화하는 역할을 한다.
✅ Salt의 주요 역할
- 동일한 비밀번호라도 서로 다른 해시 값 생성
- 만약 두 사용자가 같은 비밀번호를 사용하더라도, 다른 Salt 값을 사용하면 해시 결과가 달라진다.
- 레인보우 테이블 공격 방어
- 해식된 값을 미리 계산해 둔 레인보우 테이블을 이용한 공격을 어렵게 만든다.
- 사전 공격(Dictionary Attack) 방어
- 사전에 저장된 비밀번호 목록을 대입하는 공격을 어렵게 한다.
💡 레인보우 테이블 공격?
비밀번호를 해싱하여 저장하면 안전하다고 생각할 수 있지만, 해시 값이 예측 가능하다면 공격자에게 쉽게 노출될 수 있다.
레인보우 테이블 공격은 이러한 예측 가능한 해시 값을 미리 계산하여 빠르게 역추적하는 공격 기법이다.
Salt 없이 해싱하면 어떤 문제가 생길까?
Salt가 없는 경우, 동일한 입력 값은 항상 동일한 해시 값을 생성한다. 예를 들어, 해싱 알고리즘으로 SHA-256을 사용한다고 가정해보자.
import hashlib
passwd = "securepassword"
hashed_passwd = hashlib.sha256(passwd.encode()).hexdigest()
print(f"Hashed Password: {hashed_passwd}")
# 출력
Hashed Password: e0e6097a6f8af07daf5fc7244336ba37133713a8fc7345c36d667dfa513fabaa
이제 동일한 password를 가진 다른 사용자가 있으면, 완전히 동일한 해시 값이 저장된다. 즉, 공격자가 데이터베이스를 탈취하면 같은 해시 값을 가진 계정들을 모두 알아낼 수 있는 문제가 발생한다.
Salt를 이용한 안전한 해싱
Salt를 적용하면, 같은 비밀번호라도 해시 값이 다르게 나온다. Python에서는 `secrets` 모듈을 사용하여 랜덤한 Salt 값을 생성하고, 이를 해시와 함께 저장할 수 있다.
✅ Salt 적용 예제
import hashlib
import os
salt = os.urandom(16)
passwd = "securepassword".encode()
# salt + 비밀번호 해싱
hashed_passwd = hashlib.sha256(salt + passwd).hexdigest()
print(f"Salt: {salt.hex()}") # Salt를 hex로 변환하여 저장
print(f"Hashed Password: {hashed_passwd}")
# 출력
Salt: 5d06c33feabd059b55ee9088ce7618f3
Hashed Password: 16c53498b2f81806af0b3618489c0cfa78b5858d06dee58f2fe3b630fc8cc0f4
이제 같은 password를 입력해도, 실행할 때 마다 다른 해시 값이 생성된다.
보안성을 더 높이는 방법 (PBKDF2, bcrypt)
Salt를 적용하는 것만으로도 보안이 향상되지만, 더 강력한 해싱 기법을 사용할 수도 있다.
PBKDF2
PBKDF2는 반복 연산을 통해 연산 비용을 증가시키는 해싱 알고리즘이다.
import hashlib
import os
salt = os.urandom(16)
passwd = "securepassword".encode()
# PBKDF2 해싱 (100,000번 반복)
hashed_passwd = hashlib.pbkdf2_hmac('sha256', passwd, salt, 100000)
# 출력
print(f"Salt: {salt.hex()}")
print(f"Hashed Password: {hashed_passwd.hex()}")
bcrypt
bcrypt는 내부적으로 Salt를 포함하고 있어 별도로 관리할 필요가 없다.
import bcrypt
passwd = "securepassword".encode()
# 해시 생성 (자동으로 Salt 적용)
hashed_passwd = bcrypt.hashpw(passwd, bcrypt.gensalt())
print(f"Hashed Password: {hashed_passwd}")
# 출력
Hashed Password: b'$2b$12$iktuULL21WjeWn5SlJoCHejbBWNSMB0rj13x/nPnn2NZ0k1M.kPrG'
bcrypt의 장점은 비밀번호를 검증할 때도 간단하게 비교할 수 있다는 점이다.
input_passwd = "securepassword".encode()
if bcrypt.checkpw(input_passwd, hashed_passwd):
print("비밀번호 일치")
else:
print("비밀번호 불일치")
결론
비밀번호를 안전하게 저장하려면 다음과 같은 전략을 사용해야한다.
1. 각 사용자마다 랜덤한 Salt를 생성하여 사용
2. Salt와 해시된 비밀번호를 함께 저장 (Salt는 공개 가능)
3. 비밀번호 해싱 시 PBKDF2, bcrypt, scrypt와 같은 강력한 알고리즘 사용
4. 가능하면 해시 연산을 여러번 반복하여 연산 비용 증가 (Key stretching)
5. 비밀번호 해싱을 위한 보안 라이브러리 활용
Salt를 적용하고, 적절한 해싱 알고리즘을 사용해 보안을 강화해야한다.
'👩💻 Develope > Python' 카테고리의 다른 글
[Python] 파이썬으로 해시(Hash)와 해시테이블(Hash Table) 구현하기 (0) | 2025.02.19 |
---|---|
[Pandas] explode (0) | 2025.02.10 |
[Python] Jira API 사용하기 (0) | 2025.01.20 |
[Pandas] 데이터프레임 컬럼 순서 변경하기 (0) | 2025.01.06 |
[Pandas] 결측값 처리 (0) | 2024.12.19 |