LLM 엔지니어링13장 · REST API 와 FastAPI10 / 22← 이전목차다음 →MetaContents

13장. REST API 와 FastAPI

인증: 누구인가

회사 건물에 들어갈 때 사원증을 찍습니다. 출입 시스템은 사원증이 진짜인지, 누구의 것인지만 봅니다. 인증은 요청한 쪽이 누구인지 확인하는 일입니다. API 에서는 요청 머리글에 API 키나 토큰을 넣어 보냅니다.

요청마다 같은 비밀 글자를 보내는 API 키, 로그인으로 받은 서명된 토큰, 아이디와 비밀번호로 처음 한 번 로그인하는 세 가지를 견준 카드

왼쪽 API 키는 서버가 미리 나눠 준 비밀 글자를 요청마다 보냅니다. 프로그램끼리 부를 때 많이 씁니다. 가운데 토큰(JWT)은 로그인할 때 받아, 만료될 때까지 요청마다 보냅니다. 오른쪽 아이디와 비밀번호는 토큰을 받는 처음 한 번만 보냅니다. 여기서 사원증이 API 키나 토큰이고, 출입 시스템이 인증입니다. 다만 사원증과 달리 API 키는 글자라서 복사되면 누구나 쓸 수 있으니 더 조심해서 다룹니다.

세 가지 견주기

방법보내는 곳서버가 기억할 것맞는 때
API 키X-API-Key 머리글키의 해시와 주인서버끼리, 사내 도구
JWT 토큰Authorization: Bearer 토큰서명 비밀 키 하나로그인한 사용자, 역할이 있는 서비스
아이디와 비밀번호로그인 요청의 본문비밀번호의 해시와 소금토큰을 받을 때 한 번

비밀은 해시로 보관하고, 같은지는 안전하게 견준다

Python
import hashlib, hmac, secrets

key = secrets.token_urlsafe(24)                            # 나눠 줄 API 키(예시로 그 자리에서 만든다)
stored = hashlib.sha256(key.encode()).hexdigest()          # 서버에는 키 대신 해시만 둔다

def check(received):
    digest = hashlib.sha256(received.encode()).hexdigest()
    return hmac.compare_digest(digest, stored)             # 걸린 시간으로 비밀을 짐작하지 못하게 견준다

print(len(key), check(key), check("틀린키"))

코드에 나오는 함수

코드쉬운 뜻
secrets.token_urlsafe(24)24 바이트의 안전한 난수를 주소에 써도 되는(URL-safe) 글자로 바꾼다. 결과는 32 글자다
key.encode()글을 바이트로 바꾼다. 해시 함수는 바이트를 받는다
hashlib.sha256(...)SHA-256(Secure Hash Algorithm 256, 안전한 해시 방법, 256비트)으로 요약값을 만든다
.hexdigest()요약값(digest)을 16진수(hexadecimal) 글자 64개로 보인다
hmac.compare_digest(a, b)hmac 은 Hash-based Message Authentication Code(해시 기반 메시지 인증 코드)다. 두 요약값이 같은지, 어디서 다르든 걸리는 시간이 같게 견준다

이 코드가 뜻하는 것

사물함 관리실은 열쇠를 보관하지 않고 열쇠의 홈 모양을 본뜬 틀만 둡니다. 누가 열쇠를 가져오면 틀에 대 보고 맞으면 열어 줍니다. 여기서 열쇠가 API 키, 본뜬 틀이 해시(stored), 틀에 대 보는 일이 check 입니다. 다만 실제 본뜬 틀로는 열쇠를 다시 깎을 수 있지만, SHA-256 해시에서 원래 키를 되돌려 알아내기는 사실상 불가능하다는 점이 다릅니다.

줄하는 일쉽게 말하면
key = secrets.token_urlsafe(24)나눠 줄 키를 만든다새 열쇠
stored = hashlib.sha256(...).hexdigest()키 대신 해시만 서버에 둔다본뜬 틀만 보관
def check(received): ...받은 키를 같은 방법으로 해시해 견준다가져온 열쇠를 틀에 대 본다
print(len(key), check(key), check("틀린키"))키 길이와 두 번의 확인 결과맞는 열쇠와 틀린 열쇠

실행하면 32 True False 가 나옵니다. 키는 실행할 때마다 새로 만들어져 글자는 달라지지만 길이는 늘 32 글자입니다. 진짜 키는 통과하고 틀린 키는 거절됩니다.

작게 줄여서 눈으로 보기

같은 글과 한 글자만 다른 글의 SHA-256 요약값을 견줍니다.

Python
import hashlib

for word in ("apple", "apple", "Apple"):
    h = hashlib.sha256(word.encode()).hexdigest()
    print(word, len(h), h[:16])
출력
apple 64 3a7bd3e2360a3d29
apple 64 3a7bd3e2360a3d29
Apple 64 f223faa96f229162
결과읽는 법
64요약값은 원래 글의 길이와 관계없이 늘 16진수 64 글자다(256비트)
첫 줄과 둘째 줄같은 글은 언제나 같은 요약값이 된다. 그래서 키 대신 해시를 저장해도 견줄 수 있다
셋째 줄첫 글자의 대소문자 하나만 달라도 요약값이 완전히 달라진다. 앞 16 글자만 보였다

주의할 점

  • API 키와 서명 비밀 키는 코드에 적지 않고 환경 변수나 비밀 저장소에서 읽습니다. 교안의 코드는 발급받은_인증키 자리표시나 실행할 때 만든 시험용 키를 씁니다.
  • 키와 토큰은 글자 그대로 오가므로 실제 서비스는 HTTPS 로만 엽니다. 이 장의 실습은 내 PC 안(localhost)이라 HTTP 로 합니다.
  • 비밀번호는 sha256 한 번이 아니라, 소금(salt)을 붙여 여러 번 해시하는 pbkdf2_hmac 같은 방법으로 보관합니다(실습 6).
← 이전 절13장 · 예측 API 의 짜임다음 절 →13장 · 권한: 무엇을 해도 되나