OAuth 2.0 PKCE

OAuth 2.0 PKCE (Proof Key for Code Exchange)

PKCE(RFC 7636)는 인가 코드 흐름(Authorization Code flow)에 CSRF와 인가 코드 주입 공격을 막기 위한 확장이에요. 원래 모바일 앱을 보호하려고 설계됐지만, 인가 코드 주입을 막는 능력 덕분에 모든 종류의 OAuth 클라이언트, 심지어 클라이언트 인증을 쓰는 웹 앱에도 유용해요.

주의할 점은 PKCE가 클라이언트 인증의 한 형태도 아니고, 클라이언트 시크릿이나 다른 클라이언트 인증을 대체하지도 않아요. 공개 클라이언트를 기밀 클라이언트처럼 취급할 수 있게 해 주는 것도 아니에요.

출처: https://oauth.net/2/pkce/

동작 방식

PKCE는 두 개의 랜덤 값으로 시작해요.

  1. 클라이언트가 난수 code_verifier를 생성해요.
  2. code_challenge = BASE64URL(SHA256(code_verifier))로 변환해요. (S256 방식. 평문으로 쓰는 plain도 있지만 비권장.)
  3. 인가 요청을 보낼 때 code_challengecode_challenge_method=S256을 함께 전달해요.
  4. 인가 서버는 발급한 인가 코드를 이 challenge와 연결해 저장해요.
  5. 클라이언트가 토큰을 교환할 때 code_verifier를 함께 보내요.
  6. 인가 서버는 challenge를 다시 계산해 일치하면 토큰을 발급해요.

토큰 교환 단계에서 인가 코드가 원래 challenge와 연결된 클라이언트인지 검증되므로, 인가 코드를 가로챈 공격자는 code_verifier를 모르면 토큰을 못 받아요.

왜 중요한가요

  • 인가 코드 주입(authorization code injection) 공격 방어
  • CSRF 방어
  • 공개 클라이언트(SPA, 모바일)에서 시크릿 없이도 안전하게 인가 코드 흐름 사용 가능

현재는 시크릿이나 다른 클라이언트 인증을 쓰는 기밀 클라이언트에서도 PKCE를 함께 쓰는 것을 권장해요.

주의

  • plain code_challenge_method는 코드가 네트워크에 노출되면 무력해지므로 가능하면 쓰지 마세요.
  • PKCE는 클라이언트 인증 대체가 아니에요. 필요한 곳엔 시크릿이나 private_key_jwt 같은 클라이언트 인증을 별도로 유지해요.

더 알아보기