본문 바로가기

미래 먹거리를 위하여

[파이썬 정복하기] 라이브러리 10장 - 암호문 다루기 (맥OS 기준) — hashlib, hmac, secrets

OS: MAC

참고: 👉 점프 투 파이썬 - 라이브러리 예제 바로가기

056. 비밀번호를 암호화하여 저장하려면? ― hashlib(해시립)

✔ 되돌릴 수 없음 ✔ 파일 무결성 검증 가능 ✔ 비밀번호 검증에 사용

구분 설명 예시 결과
모듈명 hashlib import hashlib 다양한 해시 알고리즘 제공
해시(Hash) 1. 입력값을 고정 길이의 암호문으로 변환
(되돌릴 수 없음)
2. 항상 같은 입력
→ 같은 해시 출력
# 문자열을 SHA-256으로 암호화하기

import hashlib

password = "sophia123"
hash_value = hashlib.sha256(password.encode()).hexdigest()

print(hash_value)
5e884898da28047151d0e56f8dc6292773603...
주요 함수 hashlib.md5(),
hashlib.sha1(),
hashlib.sha256()
hashlib.md5("hello".encode()).hexdigest()
hashlib.sha1("hello".encode()).hexdigest()
hashlib.sha256("hello".encode()).hexdigest()
MD5, SHA1
→ 보안 약함(사용 비추천)
SHA-256 → 실무 권장
암호화 절차 (1) 문자열을 바이트로 변환
(2) 해시 함수에 넣기
(3) hexdigest()로 출력
# 파일의 SHA-256 해시 구하기 (무결성 검사)

import hashlib

h = hashlib.sha256()

with open("test.txt", "rb") as f:
    h.update(f.read())

print(h.hexdigest())
db4f391c95a031276a1209d1e667c45a3a0adaea33bb796aa75072ad0dd78bf9

비밀번호
저장 시 원칙
평문 저장 ❌
해시+salt 로 저장
=안전한 저장
# salt를 사용한 해시 (보안적으로 안전한 방식)

import hashlib

password = "sophia123"
salt = "S0LT!"      # 실전에서는 랜덤으로 생성

hash_value = hashlib.sha256((password + salt).encode()).hexdigest()

print(hash_value)
c6d689ab97b6fe8d5b5dd8f1fcac1dc48699e252ffc8c65a71a6aaa8b657bba5
salt(솔트) 해킹 방지용
추가 문자열
user마다 생성 rainbow 공격 방지

라이브러리 예제 문제:

사용자가 입력한 비밀번호를 passwd.txt 파일에 저장하는 프로그램을 만들어야 한다. 이때 비밀번호는 유추나 복호화가 불가능한 SHA256 방식으로 해싱해야 하며 이미 저장한 비밀번호가 있을 때는 입력한 비밀번호와 일치할 때만 새로운 비밀번호로 저장해야 한다. 이런 프로그램은 어떻게 만들어야 할까?

점프 투 파이썬 - 라이브러리 예제 편 10장 56번 문제 풀이 및 결과

057. 메시지 변조를 확인하려면? ― hmac(에이치맥)

- 비밀키를 이용한 안전한 메시지 무결성 검사 도구

✔ 메시지 변조 여부 확인 가능 ✔ 키 없으면 위조 불가 ✔ SHA256 등 다양한 해시 사용 가능

구분 설명 예시 결과
모듈 메시지가 중간에서
변조되지 않았는지
확인하는 보안 방식.
import hmac, hashlib HMAC 알고리즘 사용 가능
기본 예시 메시지 MAC 생성 및 검증 import hmac
import hashlib

key = b"secret_key_123"         
message = b"hello sophia"        
mac = hmac.new(key, message, hashlib.sha256).hexdigest()

print("생성된 MAC:", mac)
생성된 MAC: 2907bf80713b874dc12411b5c39ec943fb2489e46ebb5e8d5e82850ef08e5223
핵심 개념 비밀키 + 메시지 → MAC(메시지 인증 코드) 생성.
비밀키 없이는 위조 불가능.
hmac.new(key, msg, hashlib.sha256) 안전한 MAC 생성
비밀키(key) 해커가 모르는 비밀 값.
동일한 키로만 MAC 검증 가능.
key = b"secret123" 인증에 필요한 비밀키
메시지
(message)
무결성을 검증하고 싶은 데이터
(문자열·파일).
msg = b"hello sophia" 검사 대상이 되는 메시지
MAC 생성 .hexdigest() 로 16진수 해시값 생성. h = hmac.new(key, msg, hashlib.sha256).hexdigest() e3b0c4… 형태의 MAC
메시지 검증 원본 MAC 과 새로 생성한 MAC 을 비교하여 변조 여부 확인.
hmac.compare_digest(mac1, mac2)
import hmac
import hashlib

key = b"secret_key_123"
original_message = b"hello sophia"

# 원본 MAC 생성
original_mac = hmac.new(key, original_message, hashlib.sha256).hexdigest()

# (정상) 동일 메시지 검증
check_mac = hmac.new(key, original_message, hashlib.sha256).hexdigest()

if hmac.compare_digest(original_mac, check_mac):
    print("메시지가 변조되지 않았습니다.")
else:
    print("메시지가 변조되었습니다!")
메시지가 변조되지 않았습니다.


# True → 정상
False → 변조됨

라이브러리 예제 문제:

A 씨는 B 씨에게 인터넷으로 중요한 메시지를 파일로 저장하여 전달하려 한다. 하지만, 어떤 해커가 A 씨가 보낸 파일을 중간에서 가로채어 내용을 바꾼 후에 B 씨에게 다시 전달할 가능성이 있다고 한다.

이럴 때 A 씨가 보낸 파일이 해커에 의해 변조되었는지 그렇지 않은지 확인할 수 있는 프로그램을 만들려면 어떻게 해야 할까? 단, 해커가 파일의 내용을 보는 것은 상관이 없고 파일이 변조되었는지만 검증할 수 있으면 된다.

점프 투 파이썬 - 라이브러리 예제 편 10장 57번 문제 풀이 및 결과

058. 안전한 난수를 생성하려면? ― secrets(시크릿츠)

✔ 암호학적으로 안전한 난수 생성 ✔ 인증 토큰, 세션 키, 리셋 링크 등에 사용 ✔ random 대신 보안용엔 반드시 secrets 사용

구분 설명 예시 결과
모듈 보안에 강한(암호학적으로 안전한)
난수를 생성할 때 사용하는 모듈.
비밀번호, 토큰, 인증코드 등에 사용.
import secrets 보안용 난수, 토큰을 생성할 수 있게 됨
일반
random
차이
random 모듈은 통계/시뮬레이션용
(예측 가능할 수 있음).
secrets 는 예측이 매우 어려운 난수를 생성 → 보안용.
import random, secrets 로그인 토큰, 인증코드는 반드시 secrets 사용 권장
임의 바이트 생성 secrets.token_bytes(n)
→ n바이트 길이의 임의 바이트(이진 데이터) 생성.
import secrets
token = secrets.token_bytes(16) 
print(token)
16바이트 난수 
(예: b'...\x1f\xa3')
16진수 토큰 생성 secrets.token_hex(n)
→ n바이트를 16진수 문자열로 표현. URL, 로그 등에 쓰기 편함.
import secrets
token = secrets.token_hex(16)
print(token) #16바이트 → 32자리 hex 문자열
'9f2a7c1b4d8e0f3a9b2c7d1e3f4a5b6c'
URL-safe 토큰 생성 secrets.token_urlsafe(n)
→ URL에 넣어도 안전한 문자들로만 구성된 랜덤 문자열. 비밀번호 초기화 링크, 이메일 인증 토큰 등에 사용.
import secrets
token = secrets.token_urlsafe(16)
print(token)
'G3qZpZ2qZtJ3XxJ7Y8sL2A'
랜덤 정수
(범위 내)
secrets.randbelow(n)
→ 0 이상 n 미만의 임의 정수.
import secrets
code = secrets.randbelow(1000000)
print(code)  #0 ~ 999999 사이 정수 하나
482913
리스트에서 안전하게 하나 선택 secrets.choice(seq)
→ 시퀀스에서 보안용으로 안전하게 하나 선택.
import secrets
options = ["Sophia", "Alice", "Bob"]
pick = secrets.choice(options)
print(pick) # 셋중 하나 랜덤 선택
Sophia
사용 예시 (임시 비밀번호) 여러 기능을 조합해서 임시 비밀번호/토큰 만들기. import secrets
temp_pw = secrets.token_urlsafe(8)
print(temp_pw) #임시 비밀번호 생성
'_gF2aZpL-9QsXw'

라이브러리 예제 문제: 암호, 계정 인증, 보안 토큰 등의 보안 관리용으로 16진수 문자로 구성된 32자리의 난수 문자열을 생성하고자 한다(예: ffaca23207ec8cd4d7a25fc85f0fadfb). 이럴 때는 프로그램을 어떻게 작성해야 할까?

16진수는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f 총 16개 문자로 숫자를 표현하는 방법이다.

점프 투 파이썬 - 라이브러리 예제 편 10장 58번 문제 풀이 및 결과