애플리케이션 보안

OAuth 2.0

meellon 2026. 6. 23. 08:00

학습 목표

OAuth 2.0위임(delegation) 프레임워크임을 설명할 수 있다 (인증 프로토콜이 아님).

Resource Owner·Client·Authorization Server·Resource Server 역할을 구분할 수 있다.

grant type별 용도와 권장·비권장을 설명할 수 있다.

Authorization Code + PKCE 흐름을 단계별로 설명할 수 있다.

문제 상황

  • 사진 앱이 구글 비밀번호를 직접 받는다
    • 앱이 털리면 본계정까지 노출
  • SPA가 client_secret프론트 번들에 넣었다
    • 공개 클라이언트에는 secret이 없다고 봐야 한다
  • 모바일 앱이 implicit flow로 URL fragment에 토큰을 받았다
    • 로그·리퍼러·브라우저 히스토리에 유출
  • access token 하나로 모든 API에 무제한 접근
    • scope·만료·철회 설계 없음
  • "OAuth 로그인"이라고 하는데 누가 누구인지 검증이 없다
    • 인증은 OpenID Connect(7편), OAuth는 접근 위임

JWT에서 토큰 형식·검증을 봤다. 이번 편은 제3자 앱에 내 리소스 접근을 허용하는 표준 흐름이다.

본 글의 흐름·예제는 방어·구현 학습 목적이다. 타인 서비스에 대한 무단 접근·토큰 탈취 시도는 불법이다.

1. OAuth 2.0이 하는 일

OAuth 2.0 (RFC 6749) — Resource OwnerClient에게 제한된 접근위임하는 프레임워크.

  • Client가 사용자 비밀번호를 저장하지 않음
  • Authorization Server가 동의·토큰 발급
  • Resource Server(API)는 access token으로 scope 내 요청만 허용
OAuth 2.0 아닌 것
"이 앱이 내 드라이브 읽기 해도 됨" "로그인한 사용자 이메일이 누구" (OIDC)
access token 위임 세션 쿠키 대체만이 전부는 아님

2. 역할

역할
Resource Owner 사용자 (구글 계정 소유자)
Client 사진 백업 앱, SPA, 모바일 앱
Authorization Server accounts.google.com, Keycloak, Auth0
Resource Server Google Drive API, 자사 API
  • Client는 client_id로 식별, 기밀 클라이언트만 client_secret 보유
  • 토큰은 보통 BearerAuthorization: Bearer <access_token>

3. Grant type

Grant 용도 권장
Authorization Code (+ PKCE) 웹·SPA·모바일·네이티브 기본 선택
Client Credentials 서버↔서버, 배치, M2M 기밀 클라이언트만
Device Code TV·CLI 등 입력 제한 기기 해당 UX에만
Implicit (과거 SPA) 사용 금지 (RFC 폐기 방향)
Resource Owner Password 레거시 신규 금지
  • 공개 클라이언트(SPA, 모바일) — secret 없음 → PKCE 필수
  • 기밀 클라이언트(백엔드) — secret + redirect URI 고정

4. Authorization Code + PKCE

PKCE (RFC 7636) — authorization code 가로채기(code interception) 방어.

사전: code_verifier / code_challenge

code_verifier  = random 43~128 chars
code_challenge = BASE64URL(SHA256(code_verifier))   # method S256

흐름

  1. Client가 code_verifier·code_challenge 생성
  2. 브라우저를 Authorization Server /authorize로 리다이렉트
GET /authorize?
  response_type=code
  &client_id=photo-app
  &redirect_uri=https://app.example/callback
  &scope=files.read
  &state=random-csrf-token
  &code_challenge=E9Mel...
  &code_challenge_method=S256
  1. 사용자 로그인·동의
  2. redirect_uri?code=AUTH_CODE&state=... 로 돌아옴 — state 검증 필수
  3. Client(또는 BFF)가 백채널/token 호출
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https://app.example/callback
&client_id=photo-app
&code_verifier=ORIGINAL_VERIFIER
  1. access_token (+ refresh_token) 수신
  2. Resource Server API 호출
GET /v1/files HTTP/1.1
Authorization: Bearer eyJhbGciOi...
  • 토큰 교환은 반드시 서버 간(BFF·백엔드) — 브라우저에 client_secret·장기 refresh 노출 금지
  • 예시 요청 전문은 code/oauth-requests.http 참고

왜 PKCE인가

위협 PKCE 없이 PKCE
공개 클라이언트에 code 탈취 토큰 발급 가능 verifier 없으면 거부
malicious app이 동일 redirect code 재사용 시도 challenge 검증

5. Client Credentials (M2M)

서비스 계정·배치 작업 — 사용자 동의 UI 없음.

POST /token
grant_type=client_credentials
&client_id=worker
&client_secret=...
&scope=internal.jobs
  • secret은 Vault·환경변수 (13편) — 코드·이미지에 박지 않음
  • scope를 최소로 (least privilege)

6. 보안 체크리스트

항목 내용
redirect_uri 등록된 값과 exact match — 와일드카드 최소화
state CSRF 방지 — 요청마다 랜덤, 콜백에서 검증
PKCE 공개 클라이언트 S256 필수
scope 필요한 권한만 — files.read vs files.write
token 저장 SPA는 메모리·BFF — JWT 5편 저장 트레이드오프
HTTPS authorize·token·API 전 구간
token 검증 RS256 JWKS, exp·aud·iss (JWT 사용 시)
로그아웃 refresh 폐기·provider revoke endpoint
안티패턴 이유
implicit flow 토큰이 URL fragment에 노출
password grant 피싱·자격 증명 유출
long-lived access token 탈취 시 피해 확대 — refresh rotation

7. 정리

  • OAuth 2.0 = 접근 위임 — 비밀번호 대신 scope 제한 토큰
  • 웹·모바일·SPA는 Authorization Code + PKCE가 표준
  • 공개 vs 기밀 클라이언트에 따라 secret·교환 위치가 다름
  • "소셜 로그인"의 신원 확인OpenID Connect(7편)

다음에 다룰 것

  • OpenID Connect
  • ID token, identity layer

해당 내용은 RFC 6749 (OAuth 2.0), RFC 7636 (PKCE), OWASP OAuth2 Cheat Sheet 의 내용을 기반으로 합니다.

'애플리케이션 보안' 카테고리의 다른 글

인가 모델  (0) 2026.06.25
OpenID Connect  (0) 2026.06.24
JWT  (0) 2026.06.22
인증 기초  (0) 2026.06.21
TLS 심화  (0) 2026.06.20