🔐

PKCE 딥다이브 - Authorization Code 탈취를 어떻게 방어하는가

최민석·2025-02-19

🔐 PKCE 딥다이브: Authorization Code 탈취를 어떻게 방어하는가

1. 🧭 PKCE란?

  • PKCE(Proof Key for Code Exchange) **는 모바일 앱, SPA(React, Flutter 등)처럼 client_secret을 안전하게 저장할 수 없는 환경에서도 Authorization Code Flow를 안전하게 사용할 수 있게 만든 확장 기술이다.

OAuth 2.0의 주요 취약점 중 하나인 Authorization Code 탈취를 막기 위한 보안 계층으로, 2015년 RFC 7636에서 표준화되었다.


2. 🔓 기존 OAuth 2.0의 보안 문제

⚠️ 문제: Authorization Code 탈취 가능

기존 OAuth 2.0 흐름에서는, 사용자가 로그인한 뒤 Authorization Code가 다음과 같이 리다이렉트 URL을 통해 전달된다:

https://yourapp.com/callback?code=abc123xyz

이 코드는:

  • 브라우저 주소창
  • 브라우저 히스토리
  • 리퍼러(Referer) 헤더
  • 악성 확장 프로그램
  • 로그 기록

을 통해 제3자에 의해 탈취될 수 있음

→ 탈취한 공격자가 이 code를 Google 등에 보내면 access_token, id_token을 받아 사용자 계정을 탈취할 수 있음


3. 🧠 PKCE의 작동 원리

PKCE는 다음 두 가지 값을 중심으로 동작한다:

항목 설명
code_verifier 클라이언트가 생성하는 고유한 임의 문자열 (비밀번호 역할)
code_challenge code_verifier를 SHA256 해시 후 base64-url 인코딩한 값

인증 요청 시:

/authorize?response_type=code
           &code_challenge=abcXYZ
           &code_challenge_method=S256

토큰 요청 시:

POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=abc123xyz
&code_verifier=purelyRandomValue

서버 내부 로직:

  • 서버는 code_verifier로 code_challenge를 재생성
  • 초기 요청에서 받은 code_challenge와 일치하는지 검증
  • 일치하지 않으면 토큰 발급 ❌

4. 🤔 그럼 code는 아직도 노출되는 거 아닌가?

O. PKCE를 사용해도 Authorization Code 자체는 여전히 브라우저 주소창에 노출된다.

하지만 이제 그 코드만으로는 access_token을 받을 수 없다.

왜냐하면:

  • Google(Authorization Server)은 토큰 발급 시 반드시 code_challenge에 대응하는 code_verifier도 같이 받아야 함
  • 이 code_verifier는 앱 내부에서만 존재하고, TLS를 통해서만 서버로 전달됨
  • 탈취된 code에는 code_verifier가 없으므로, Google은 토큰을 절대 발급하지 않음

5. 🛡️ PKCE가 실질적으로 막아주는 공격

공격 시도 PKCE 없이 PKCE 적용 시
Authorization Code 탈취 토큰 발급 가능 → 계정 탈취 code_verifier 없으면 토큰 발급 불가
중간자 공격 (MITM) code 탈취 후 토큰 교환 가능 code_verifier 없으면 무력화
악성 확장 프로그램 주소창에서 code 추출 가능 code만으론 무용지물

6. 🧾 요약 정리

  • PKCE는 code 자체의 노출을 막는 게 아니라, 노출되더라도 무력화시키는 방식
  • 모바일 앱, SPA에서 반드시 사용해야 함
  • 전송 계층 보안(TLS) + PKCE의 이중 방어로 안전한 OAuth 인증 구현 가능