파이널 프로젝트 회고록 - 로그인 2편, PKCE 도입
2025년 03월 25일
ProgrammersBlogReactFinalProjectFrontendJWTLogin

기존의 로그인 구현 방식: HttpsOnly, Secure쿠키
- 프론트엔드에서 소셜 로그인 제공자(구글, 카카오 등)로 인증 요청
- 사용자가 소셜 로그인 제공자에서 인증 완료
- 프론트엔드가 소셜 로그인 제공자로부터 인증 코드를 받음
- 프론트엔드가 이 코드를 사용해 소셜 로그인 제공자로부터 사용자 정보와 토큰을 직접 획득
- 프론트엔드가 이 사용자 정보를 백엔드로 전송
- 백엔드는 이 정보를 신뢰하고 JWT를 발급
PKCE(Proof Key for Code Exchange)를 도입하게 된 배경
문제점:
백엔드는 받은 사용자 정보가 실제로 신뢰할 수 있는 프론트엔드 클라이언트에서 왔는지 검증할 방법이 없다. 즉, 악의적인 제3자가 정상적인 소셜 로그인 과정을 모방하여 위조된 사용자 정보를 백엔드에 직접 전송해도 백엔드는 이를 구분할 수 없는 것이다.
PKCE 방식의 원리
PKCE(Proof Key for Code Exchange)는 OAuth 2.0의 확장 메커니즘으로, 원래 모바일 앱과 같은 공개 클라이언트를 위해 설계되었지만 웹 애플리케이션에서도 유용하다.
PKCE의 작동 원리:
- 증명 키 생성: 클라이언트가 인증 프로세스를 시작하기 전에 랜덤한 문자열(Code Verifier)을 생성
- 챌린지 생성: 이 Code Verifier를 단방향 해시 함수(SHA-256)로 변환하여 Code Challenge 생성
- 챌린지 전송: 인증 요청 시 Code Challenge만 전송
- 증명 검증: 인증 완료 후 원본 Code Verifier를 전송하여 서버가 같은 해시 알고리즘으로 검증
단방향 해시의 특성상, Code Challenge만으로는 원본 Code Verifier를 알아낼 수 없습니다. 따라서 전체 인증 과정에서 같은 클라이언트가 일관되게 참여했음을 증명할 수 있다.
새로운 소셜 로그인 흐름
PKCE를 적용한 새로운 소셜 로그인 흐름은 다음과 같다.
1. Pre-Login 단계 (새로 추가)
- 프론트엔드가 랜덤한 Code Verifier 생성
- Code Verifier를 SHA-256으로 해싱하여 Code Challenge 생성
- 프론트엔드가 백엔드에 Code Challenge와 해시 방식을 전송
- 백엔드가 이 정보를 JWT에 넣어 프론트엔드에 반환
2. 소셜 로그인 단계 (기존과 동일)
- 프론트엔드가 소셜 로그인 제공자로 인증 요청
- 사용자가 소셜 로그인 제공자에서 인증 완료
- 프론트엔드가 소셜 로그인 제공자로부터 코드 수신
- 프론트엔드가 이 코드로 사용자 정보와 토큰 획득
3. 백엔드 로그인 단계 (확장)
- 프론트엔드가 다음 정보를 백엔드로 전송:
- 소셜 로그인 사용자 정보
- Pre-Login 단계에서 받은 JWT
- 원본 Code Verifier
- 백엔드가 다음 검증 수행:
- JWT의 무결성 검증(위변조 여부)
- JWT에서 Code Challenge 추출
- 받은 Code Verifier를 해싱하여 JWT의 Code Challenge와 일치 여부 확인
- 일치할 경우에만 인증 토큰 발급
💡 달라지는 핵심 부분
기존 방식에서 새로운 PKCE 방식으로 전환됨으로써 달라지는 핵심 부분은:
- 클라이언트 인증 메커니즘 추가:
- 이전: 백엔드는 클라이언트를 검증하지 않고 소셜 로그인 정보만 신뢰
- 이후: 백엔드는 Code Verifier/Challenge 쌍을 통해 클라이언트의 정당성 검증
- 2단계 인증 프로세스:
- 이전: 소셜 로그인 후 바로 백엔드 인증
- 이후: Pre-Login → 소셜 로그인 → 백엔드 인증의 3단계로 확장
- 보안 강화:
- 이전: 악의적인 제3자가 소셜 로그인 정보만 알면 위조 가능
- 이후: 악의적인 제3자는 Code Verifier를 알 수 없어 위조 불가능
- 암호학적 증명:
- 이전: 단순 정보 전달 기반 신뢰
- 이후: 암호학적 일방향 해시 함수 기반 증명
✅ 보안 이점
이 변경을 통해 얻는 보안 이점:
- 클라이언트 검증: 백엔드는 요청이 정당한 클라이언트에서 온 것인지 확인할 수 있다.
- 세션 바인딩: 소셜 로그인 과정이 시작된 클라이언트와 완료된 클라이언트가 동일함을 보장한다.
- 중간자 공격 방지: 통신이 가로채이더라도 공격자는 Code Verifier를 알 수 없어 인증을 완료할 수 없다.
- 요청 위조 방지: 다른 출처에서 위조된 소셜 로그인 정보를 보내더라도 유효한 Code Verifier/JWT 없이는 인증이 불가능.
이러한 PKCE 기반 인증 방식은 백엔드 시스템이 클라이언트의 신원을 보다 확실하게 검증할 수 있게 하여, 전체 인증 시스템의 신뢰성과 보안성을 크게 향상시킨다.