[TIL 65-1일 차] 유저 관리 기능

3. 기본 인증과 인코딩

3-01. 기본 인증(Basic Authentication)

1) 기본 인증

기본 인증HTTP 표준 인증 방식 중 하나로, RFC 7617에 정의되어 있다.

  • 클라이언트: 사용자 이름과 비밀번호를 콜론(:)으로 연결 ➡️ username:password
  • 인코딩: 연결한 문자열을 Base64로 인코딩 ➡️ dXNlcm5hbWU6cGFzc3dvcmQ=
  • 서버 요청: 인코딩한 문자열을 Authorization 헤더에 담아 요청 전송
GET /mypage HTTP/1.1
Host: example.com
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
  • 서버 동작
    • Authorization 헤더 확인
    • Basic 접두사 제거 후 Base64 디코딩
    • username:password 추출
    • 서버 저장소의 자격 증명과 비교 후 인증 성공 여부 결정


2) 기본 인증의 한계와 보안 위험성

  • 인코딩 ≠ 암호화 : Base64는 단순 인코딩, 보안 기능 X
  • 재전송 위험: 요청마다 자격 증명이 반복 전송되므로 탈취 위험성이 높음
  • 저장소 문제: 서버는 사용자의 비밀번호를 해시 등의 방법으로 안전하게 저장해야 함
  • 현대적 대체 수단 필요: 세션 기반 인증이나 토큰 기반 인증(JWT 등)이 일반적으로 사용됨


3-02. 인코딩과 Base64URL

1) 인코딩(Encoding)

데이터를 다른 표현 규칙으로 바꾸는 것

  • 내용 자체는 변하지 않고, 표현 방식만 변하는 것
  • A는 컴퓨터 내부에서 2진수로 01000001로 저장됨

필요성

  • 소통: 서로 다른 언어나 기기에서 같은 정보를 주고받기 위해
  • 전송 안정성: 어떤 통로는 한글이나 특수 문자를 제대로 못 읽음
  • 저장 호환성: 텍스트 파일, 이메일, 웹 요청 등에서 문제가 생기지 않도록 도움

예시

  • 문자 인코딩 : 이모지가 상대방과 똑같이 보임
  • URL 인코딩 : 주소창에 공백 대신 %20이 들어가는 것
  • 동영상 인코딩 : 유튜브에서 같은 영상을 240p~1080p로 선택 가능한 이유
  • QR 코드 : 흑백 점들이 문자, 링크, 숫자로 변환되는 과정
  • 인코딩 순서 예시: 안녕! ➡️ UTF-8 규칙 적용 ➡️ 11101111.... ➡️ 다른 기기에서 디코딩 ➡️ 안녕!


2) Base64 인코딩

다른 인코딩이 필요한 이유

  • 이메일, HTTP 헤더 같은 통로는 특수 문자나 바이너리(사진, 음악) 파일을 직접 담기 어려움
  • 그래서 모든 데이터를 알파벳 + 숫자만으로 바꿔서 안전하게 보내는 방식이 필요함
  • 이것이 Base64
  • 텍스트 전송만 가능한 채널에 안전한 포장지 역할을 함
  • 다만, 데이터가 4/3배로 늘어나므로 대용량 데이터에는 적합하지 않음

원리

  • 3 Byte(24 bit) ➡️ 6 bit씩 자름 ➡️ 4개의 문자로 바꿈
  • 총 64개의 안전한 문자(A-Z a-z 0-9 + /)만 사용
  • 나머지가 부족하면 = 기호로 채움


3) Base64URL 인코딩

  • URL에서는 +, /, = 같은 문자가 문제를 발생시킬 수 있음.
  • 그래서 안전하게 “+ ➡️ _”로, “/ ➡️ -”로, “= 제거”로 바꾼 게 Base64URL


3-03. 기본 인증 보안 고려사항

1) HTTPS의 필요성

  • HTTP의 전송 방식 : 평문(암호화 없음)
    • Basic Auth를 사용하면 Authorization 헤더가 그대로 노출
  • HTTPS의 전송 방식 : TLS/SSL로 암호화
    • 전송 구간을 암호화하여 중간에서 패킷을 보더라도 내용을 알 수 없음


2) HTTPS 내부 동작

  • 통신 과정에서 대칭키 암호화와 비대칭키 암호화를 함께 사용함
    • 비대칭키 방식은 안전하지만 연산 비용이 커서 모든 데이터를 암호화하기에는 비효율적
    • 대칭키 방식은 빠르지만, 통신에 사용할 키를 처음에 안전하게 공유해야 하는 문제 존재
    • 따라서 HTTPS는 처음 연결 시 비대칭키 기반으로 안전하게 세션 키를 만들고, 이후 실제 HTTP 데이터는 이 세션 키를 이용해 대칭키 방식으로 암호화
  1. 브라우저가 서버에 HTTPS 통신을 하겠다는 신호를 보냄
    • 지원 가능한 암호화 방식 목록을 함께 보냄
  2. 서버는 사용할 암호화 방식을 고르고, 자신이 신뢰할 수 있는 서버임을 나타내는 디지털 인증서(공개키 포함)를 보냄
  3. 브라우저는 서버의 공개키로 임시 대칭키(세션키)를 암호화해서 전달
  4. 서버는 개인키로 이를 복호화하여 같은 대칭키를 얻음
  5. 이후 모든 HTTP 요청/응답은 이 대칭키로 암호화되어 전송됨
  • 예시
    • HTTP : 우편엽서에 주소, 내용, 비밀번호까지 다 작성해서 보내는 것
    • HTTPS : 봉투에 넣어 봉인 후 보내는 것


3) 자격 증명 노출 위험성

  • Base64는 단순 인코딩일 뿐 암호화는 아님
  • 그래서 Authorization 헤더를 훔치면 빠르게 username:password를 알 수 있다.


4) 현대 웹 애플리케이션에서 활용 여부

안 쓰이는 이유

  • 매 요청마다 ID/PW를 보내는 구조라 매우 위험
  • 세션/토큰 기반 인증이 더 안전하고 효율적

사용되는 곳

  • 내부 시스템, 테스트용 API, 간단한 인증에만 제한적 사용

4. Authorization 헤더와 토큰 기반 인증

4-01. Authorization 헤더

HTTP 요청에서 인증 정보를 서버로 전달하기 위해 사용하는 표준 헤더

  • 용도: 서버가 클라이언트의 신원을 확인하고 보호된 리소스로의 접근 권한을 부여하는데 사용
  • 예시: Authorization 헤더를 사용해 Basic 인증 자격 증명을 보낸 요청
    GET /protected-resource HTTP/1.1
    Host: example.com
    Authorization: Basic dXNlcjpwYXNz
    


1) 구조와 기본 형식

  • 인증 방식
    • 어떤 인증 방법을 사용하는지 식별
    • 예시
      • Basic, Bearer, Digest
  • 자격 증명 또는 토큰
    • 인증 데이터 (암호화, 인코딩된 값 등)
    • 예시
      • dXNlcjpwYXNz, eyJhbGciOi...
  • 최종 형태
    • Authorization: <인증방식> <인증정보>
    • Basic 인증
      • 예시: Authorization: Basic dXNlcjpwYXNz
      • RFC 7617에서 정의한 인증 방식인 Basic을 사용
      • username:passwordBase64로 인코딩하여 전송
      • 단순하지만 보안에 취약 ➡️ 반드시 HTTPS와 함께 사용해야 함
    • Bearer 토큰 인증
      • 예시: Authorization: Bearer eyJhbGciOi...
      • RFC 6750에서 정의된 방식으로, 보통 액세스 토큰(JWT 등)을 전달합니다.
      • “이 토큰 가진 자(bearer)는 접근 권한이 있다”는 의미
      • API 서버를 설계할 때 일반적으로 많이 사용함 (+ HTTPS)
    • Digest 인증
      • 예시: Authorization: Digest username="Mufasa", [realm="testrealm@host.com](mailto:realm=%22testrealm@host.com)", ...
      • nonce와 해시 알고리즘을 이용해 암호를 직접 전송하지 않고 검증
      • 과거에는 많이 사용했으나, 현재는 거의 Bearer/JWT 방식으로 대체됨


2) 세션 기반 인증과의 차이점

구분 세션 기반 인증 Authorization 헤더 기반 인증
인증 정보 저장 위치 서버 (세션 저장소) 클라이언트 (토큰 등)
전송 방식 쿠키(Cookie: SESSION=...) 헤더(Authorization: ...)
상태 관리 서버가 상태(state)를 유지 서버는 무상태(stateless)로 동작 가능
확장성 서버 확장 시 세션 동기화 필요 토큰만 검증하면 되어 확장성 높음


3) Authorization 헤더 기반 인증 workflow


4-02. 토큰 기반 인증

토큰은 특정 리소스에 대한 접근 권한을 부여함


1) 토큰 기반 인증의 특징

  • 토큰에 포함된 인증 정보는 서버가 별도로 저장하지 않음
  • 생성된 토큰을 HTTP Authorization 헤더에 담아 전송
  • 토큰 안에 사용자 정보가 포함되므로 세션에 비해 네트워크 트래픽이 많을 수 있다.
    • 토큰이 매 요청마다 함께 전송되기 때문
  • 서버는 토큰 자체를 관리하지 않으므로 보안성 측면에서 신중한 설계가 필요
  • 인증 상태를 서버에 저장하지 않기 때문에 확장성(Scalability)면에서 매우 유리함
  • 토큰 유출 시 위험
  • 평문 그대로 전달되므로 반드시 TLS(HTTPS)로 전송해야 함
  • 토큰은 만료되기 전까지 기본적으로 무효화 불가능
    • 단, Redis 같은 인메모리 DB에 블랙리스트 형태로 저장하고 짧은 만료 시간을 부여하여 보완 가능


2) 세션 기반 인증과 토큰 기반 인증 비교

구분 세션 기반 인증 토큰 기반 인증
상태 관리 서버에 세션 저장소 필요 서버 상태 저장 불필요, 토큰만 검증
확장성 세션 공유 필요 (예: Redis) 서버 확장에 유리
저장 위치 브라우저 쿠키 로컬 스토리지, 세션 스토리지, 쿠키 등
보안 위험 세션 탈취 토큰 유출
무효화 세션 만료 시 서버에서 무효화 가능 만료 전까지 기본적으로 무효화 불가


3) 토큰 기반 인증 workflow


4-03. JWT(JSON Web Token)

JWT는 데이터를 안전하고 간결하게 전송하기 위해 고안된 인터넷 표준 인증 방식

  • 애플리케이션 보안에서 JWT는 출입 카드와 비슷한 개념으로, 특정 권한을 가진 사용자가 시스템을 이용할 수 있게 해줌
  • JWT 공식 사이트: https://www.jwt.io/

토큰 기반 인증(Token-based Authentication)에서 가장 범용적으로 사용됨

  • JWT는 서버 확장성이 중요한 마이크로서비스 아키텍처에서 유용


1) JWT 구조

세 부분으로 나뉘며, 각각 .으로 구분됨

Header (헤더)

  • 어떤 알고리즘으로 서명했는지, 어떤 타입의 토큰인지 정의
{
  "alg": "HS256",
  "typ": "JWT"
}
  • alg : 사용할 서명 알고리즘 (예: HMAC SHA256)
  • typ : 토큰 타입 (JWT)
  • Base64URL로 인코딩하면 JWT의 첫 번째 부분이 됨

Payload (페이로드)

  • 사용자 정보와 클레임(Claim) 데이터가 담김
{
  "sub": "user123",
  "name": "Alice",
  "iat": 1516239022
}
  • 사용자의 고유한 정보와 권한, 토큰 발급 시간(iat) 등이 포함됨
  • 민감한 정보를 포함 금지
  • Base64URL로 인코딩하면 JWT의 두 번째 부분이 됨

Signature (서명)

  • 헤더와 페이로드가 변조되지 않았음을 검증
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)
  • 서버의 비밀키(Secret Key)로 생성
  • 클라이언트가 보낸 토큰이 변조되지 않았다는 것을 검증함


2) JWT workflow


3) JWT 사용 예시

앱 A가 Gmail과 연동되어 이메일을 읽어와야 하는 경우

(1) 사용자가 Gmail 인증서버에 로그인

(2) 인증에 성공하면 서버는 JWT 발급

(3) 앱 A는 JWT를 Authorization 헤더에 넣어 Gmail API 요청

(4) Gmail 서버는 JWT의 서명을 검증 후 이메일 데이터를 반환

➡️ 사용자는 Gmail 비밀번호를 앱 A에 제공하지 않아도 안전하게 데이터 연동 가능


4) JWT 실무 팁

잘못 사용하면 보안에 취약할 수 있음

민감한 정보 포함 금지

  • JWT는 Base64URL로 인코딩되어 있을 뿐 암호화되어 있지 않음

토큰 만료 시간 설정

  • 만료 시간(exp)을 반드시 설정
  • 만료 시간이 없는 토큰은 탈취될 경우 영구적으로 악용될 수 있음

HTTPS 사용

  • JWT는 네트워크를 통해 전달되므로, 반드시 HTTPS를 통해 암호화된 채널에서만 전송

저장 위치 주의

  • 로컬 스토리지(localStorage) 대신 HTTPOnly 쿠키 또는 보안이 강화된 세션 스토리지 사용을 권장
  • 로컬 스토리지는 XSS 공격에 취약

토큰 무효화 전략

  • 기본적으로 JWT는 발급 후 만료 전까지 무효화할 수 없음
  • 이를 보완하기 위해 서버 측에서 블랙리스트를 관리하거나 Redis 같은 인메모리 DB 활용


4-04. Refresh 토큰의 이해

보안성과 편의성을 동시에 만족하기 위해서 Access 토큰과 Refresh 토큰을 분리하는 방식을 사용


1) Access 토큰과 Refresh 토큰의 역할

구분 Access 토큰 Refresh 토큰
목적 리소스 서버 접근 권한 부여 새로운 Access 토큰 발급 요청
유효 기간 짧음 (분 단위 ~ 수십 분) 김 (일 단위 ~ 수주)
보관 위치 클라이언트(브라우저/앱) 클라이언트 안전 영역(예: Secure Storage)
보안 리스크 탈취 시 제한된 시간만 사용 가능 탈취 시 장기간 사용 가능 → 강화된 보안 필요
  • Access 토큰 : 실제 API 요청에 사용
  • Refresh 토큰 : Access 토큰 재발급 용도


2) 토큰을 나누는 이유

보안성 강화

  • Access 토큰은 짧은 만료 시간으로 발급 ➡️ 탈취되더라도 금방 무력화됨
  • Refresh 토큰은 더 오래 유지되지만, 오직 재발급 요청에만 사용됨

사용자 경험 개선

  • 사용자가 매번 로그인할 필요 없음
  • Access 토큰이 만료되면 Refresh 토큰을 이용해 자동으로 새 Access 토큰을 발급


3) 토큰 갱신 workflow


4) 토큰 만료 및 무효화 처리

Access 토큰 만료

  • 기본적으로 수 분 ~ 수십 분 ➡️ 탈취 시, 피해를 최소화하기 위함

Refresh 토큰 만료

  • 보통 일 단위 또는 주 단위
  • 장기간 보관되므로 DB 저장 후 화이트리스트/블랙리스트 방식으로 관리하는 경우가 많음

무효화 전략

  • 강제 로그아웃: 서버 DB에서 Refresh 토큰을 제거
  • 토큰 로테이션: Refresh 토큰 사용 시마다 새 Refresh 토큰 발급, 이전 것 무효화


5) Access 토큰과 Refresh 토큰 실무 팁

  • 모바일 앱은 Refresh 토큰을 Secure Storage(Keychain, Keystore 등)에 저장
  • 브라우저 환경에서는 Refresh 토큰을 쿠키(HttpOnly + Secure + SameSite)로 관리

Leave a comment