보물창고 블로그

Oauth 파헤치기 본문

웹 개발/Computer Science Note

Oauth 파헤치기

홋 메 2025. 5. 2. 11:19
728x90

이번 포스트에서는 Oauth, JWT에 대해 알아보고자 합니다.

 

Oauth는 Open AUthrization의 줄임말로, 사용자의 비밀번호를 직접 제공하지 않고도 제3자 앱이 사용자 자원(정보,권한 등)에 접글할 수 있도록 권한을 위임하는 기술입니다. 

Oauth는 그럼 언제 사용해야할까요? 아래와 같이 대표적으로 4가지 경우가 있습니다.

1. 소셜 로그인 구현 시

사용자가 Google, Kakao, Naver 계정으로 로그인할 수 있게 할 때→ OAuth로 인증 & 사용자 정보 API 사용

  • 예: “Google로 로그인”, “카카오로 로그인”

2. 사용자 자원에 접근해야 할 때

사용자가 허락한 범위 내에서 그 사람의 데이터를 가져오거나 조작해야 할 때

  • 예:
    • 사용자의 Google Drive 파일 목록 보기
    • Spotify에서 사용자의 재생목록 불러오기
    • 사용자의 GitHub 레포지토리 읽기/쓰기

3. 서비스 간 연동이 필요할 때

한 서비스가 다른 서비스의 API를 대리로 호출해야 할 때

  • 예:
    • 슬랙 봇이 유저 대신 메시지 보내기
    • 노션 플러그인이 사용자 노션 페이지 수정
    • Zapier, IFTTT 같은 자동화 플랫폼

4. 다중 플랫폼 서비스에서 SSO 또는 권한 제어가 필요할 때

하나의 인증으로 여러 시스템을 넘나들 수 있어야 할 때

  • 예: 회사 내부 시스템 로그인 (OAuth + OpenID Connect 조합)

제가 최근에 진행하는 프로젝트도, figma라는 디자인 툴에 대해 SSO 로그인 기능이 필요해서 Oauth를 사용하여 구현하였습니다.

다만 최근에 새로 생긴 개념이 있는데, 바로 PKCE(Proof Key for Code Exchange)입니다.  PKCE (Proof Key for Code Exchange, 픽시)는 OAuth 2.0 Authorization Code Flow의 보안 강화 버전입니다. 특히 **모바일 앱이나 SPA(싱글 페이지 앱)**처럼 클라이언트 비밀(Client Secret)을 안전하게 숨길 수 없는 환경에서 사용됩니다. PKCE는 왜 나오게 되었을까요?

아래 Oauth 로그인 다이어그램에서 PKCE가 나오게 된 배경에 대해 알아보겠습니다.

Step(1) 앱에서 시스템 또는 브라우저를 통해 인증요청을 합니다. 이 단계에서 앱은 리디렉션 URI도 제공합니다.

Step(2) 시스템 또는 브라우저에서 로그인을 하면 인증 요청은 OAuth 2.0 인증 서버로 전달됩니다. OAuth는 TLS 사용을 요구하기 때문에, 이 통신은 TLS에 의해 보호되며 가로챌 수 없습니다. 여기서 TLS란 TLS (Transport Layer Security): HTTPS의 기반이 되는 암호화 통신 프로토콜입니다. 

Step(3) 인증서버에서 인증코드를 Step(1)에서 제공한 리디렉션 URI로 반환하게 됩니다. (callback 이라고 보시면 됩니다.)

이 단계에서, 만약 악의적인 앱이 리디렉션 URI의 핸들러로 등록되어 있으면, 악의적인 앱은 인증 코드를 가로챌 수 있습니다. 인증 코드를 갖고 공격자는 단계 (5.a)와 (6.a)에서 액세스 토큰을 요청하고 얻을 수 있습니다. 이를 방지하고자 만든 것이 바로 PKCE입니다.

 

PKCE를 적용하면 Step(1)에서 앱에서 인증 코드를 요청할 때, 애플리케이션은 먼저 랜덤 코드 검증기를 생성하고 로컬에 저장합니다.

그런 다음 이 코드 검증기를 특정 암호화 알고리즘을 사용하여 코드 챌린지로 변환합니다. 애플리케이션은 인증 코드 요청 중에 코드 챌린지와 암호화 알고리즘 방법 둘 다를 인증 서버에 보냅니다. 일반적으로는 SHA-256을 사용합니다. 그 이유는 SHA-256은 단방향 해시 함수로, code_challenge만으로는 code_verifier를 유추할 수 없습니다. 따라서 공격자가 Authorization Code를 탈취하더라도, code_verifier가 없으면 Access Token 요청에 실패합니다. 아래 예시를 참고하면 좋습니다.

// 예를 들어:
const code_verifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"

// SHA256 + base64url encoding
const code_challenge = BASE64URL-ENCODE(SHA256(code_verifier))
// 결과: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM

이렇게 만든 code_challenge를 Step(1)에서 인증요청 시 추가하고,  인증코드로 서버에서 AccessToken을 요청할 때 code_verifier를 전달하여 서버에서 탈취자가 아닌, 정상적인 서버에서 온 요청인지를 확인할 수 있습니다. 따라서 위 다이어그램에서 악성 앱이 인증 코드를 탈취하여 accessToken을 얻게되는 4.a, 5.a, 6.a Step들을 방지할 수 있습니다.  다음 포스트에서는 AccessToken의 근간인 JWT에 대해 알아보겠습니다.

 

참고문헌

 

'웹 개발 > Computer Science Note' 카테고리의 다른 글

CORS(Cross-Origin Resource Sharing) 파헤치기  (1) 2025.05.18
Spring Interceptor 파헤치기  (0) 2025.05.11
Spring filter 파헤치기  (0) 2025.05.10
JWT 파해치기  (0) 2025.05.03
Comments