OAuth는 외부 애플리케이션이 사용자 비밀번호를 알지 않고도 제한된 자원에 접근할 수 있게 해주는 시스템입니다.
보통 소셜 로그인(구글, 카카오)을 구현할 때 사용됩니다.

OAuth의 인증과정은 구현마다 다르지만 아래와 같은 과정을 거칩니다.
- 사용자가 로그인 요청을 합니다.
브라우저 혹은 별도의 창이 열리며 아이디와 비밀번호를 입력할 수 있습니다.- 사용자가 로그인을 하게 되면 OAuth 서버에서 확인 후 올바르다면 사용자 정보 접근을 위한 코드를 줍니다.
- 클라이언트는 코드를 서버로 넘깁니다.
- 서버는 OAuth 서버를 통해 코드가 바른지 확인하고 정보를 요청합니다.
- OAuth 서버는 코드가 바르다면 정보를 줍니다.
- 서버는 정보를 저장하고 액세스 토큰과 리프레시 토큰을 발급하여 클라이언트로 보내주게됩니다.
조금 많이 정보가 왔다갔다하지만 이 과정에서는 TLS가 적용되어있어 악의적인 공격자가 중간에 가로채더라도 정보를 볼 수 없습니다.
그렇다면 완벽하게 안전할까요?
이제 여기서 문제가 발생할 수 있는 부분은 인증 후 클라이언트로 코드를 전달해주는 부분입니다.
브라우저는 인증 후 요청한 클라이언트를 다시 호출하여 리다이렉트를 통해 코드를 넘기게 됩니다.
이때 전달할 클라이언트를 식별하기 위한 수단으로 앱의 이름과 같은 URI Scheme을 이용합니다.
OS마다 다르지만 Android의 경우 만약 Scheme이 같은 앱이 여러개 있다면 그 중 사용 할 앱을 선택하게 됩니다.
악의적인 공격자가 대상앱의 URI scheme을 알아내고 같은 scheme을 가지는 악성앱을 사용자에게 설치해두었다면, 선택과정에서 사용자가 잘못 된 앱을 선택하거나, 이미 기본으로 실행하게 설정하여 자동으로 악성앱이 실행될 수 있습니다.

이렇게 되면 OAuth 접근을 위한 코드가 공격자에게 넘어가게 되고 공격자는 아무런 문제없이 3~6번 과정을 진행하여 서버의 정보에 접근 할 수 있는 액세스 토큰을 얻게됩니다.
공격자는 마치 정상적인 사용자처럼 탈취당한 사용자의 정보에 접근할 수 있게 됩니다.
스마트폰의 보안이 발달함에 따라 임의의 앱을 사용자 모르게 설치하는 것이 쉽지 않아졌지만, 발생시 꽤 치명적인 문제입니다.
이런 문제를 막기위해 PKCE가 등장하게 됩니다.
PKCE의 원리는 간단합니다.
너가 로그인을 요청한 클라이언트라는 걸 증명해!
PKCE가 적용되면 OAuth 서버는 코드 발급시, 정보 요청시 마다 임의의 code verifier를 요구하게 됩니다.
이 code verifier는 정해진 값이 아니고 클라이언트에서 만드는 무작위 값으로 요청을 보내는 클라이언트만 알고 있기에 오직 해당 클라이언트만 정보를 받을 수 있게 됩니다.
- 클라이언트는 로그인 요청시
code verifier를 만들어 같이 보냅니다.code verifier를 받은 OAuth 서버는 코드를 생성함과 동시에code verifier를 해싱한code challenge를 만들어 코드와 매칭시킵니다.- 코드를 받은 클라이언트는 서버로 코드와 함께
code verifier를 보냅니다.- 서버는 OAuth 서버로 코드와 함께
code verifier를 보내 정보를 요청합니다.- OAuth 서버는 입력으로 들어온
code verifier를 해싱한 값과 코드에 매칭되어있는code challenge가 같은지 확인합니다.- 같다면 정보를 주고, 아니라면 거부합니다.
- 서버는 정보가 온다면 액세스 토큰을 클라이언트로 보냅니다.

이렇게 되면 이전의 클라이언트로 코드를 주는 과정에서 코드가 탈취되더라도 code verifier를 모르기에 공격자는 3~7번 과정을 진행 헐 수 없게됩니다.
또한 code verifier는 매 요청마다 다른 랜덤값이고, 전송시 TLS가 적용되어 공격자는 탈취할 수 없게됩니다.
OAuth서버 측에 저장되는 값 또한 code verifier 자체가 아니라 이를 해싱한 code challenge 이기에 OAuth 서버에서 탈취되어도 안전합니다.
보면 PKCE를 적용하기 위해서는 OAuth 서버가 이를 지원하는 것이 중요합니다.
한번 국내에서 OAuth 로그인에 많이 쓰는 몇가지 사이트만 한번 조사해보겠습니다.

구글은 로그인시 권장 항목으로 code_challenge를 전달 받고 있습니다.

카카오는 OpenID Connect 라는 별도의 로그인 방식으로 지원합니다.
(iOS, Android에서 쓰는 SDK는 이를 별도로 신경쓰지 않아도 자동으로 지원합니다.)

네이버 또한 카카오와 마찬가지로 별도의 로그인 방식으로 OIDC와 함께 지원합니다.
자세히 설명된 문서를 찾지 못했지만 애플 또한 네이버, 카카오와 같이 OIDC 와 함께 PKCE를 지원합니다.
PKCE는 공격자의 토큰 탈취를 막기위한 중요한 방어책입니다.
우리가 아는 대부분의 OAuth 로그인이 PCKE를 지원하는 만큼 이왕 소셜 로그인을 구현한다면 조금 복잡하더라도 PKCE를 적용해보면 어떨까요?