Skip to content

OAuth2 동작 과정

개요


GAMERS 프로젝트를 진행하면서 유저가 회원가입을 할 때, Email, Password 로 진행하기에는 너무 귀찮은 작업아닌가? 라는 고민을 하게 되었다.

작성을 하고 있는 나조차도 게임을 좋아하는 사람이기에 회원가입이라는 과정이 얼마나 귀찮은 작업인지 알고있었기 때문이다.

그래서 Gamer 들이 가장 많이 쓰는 로그인 방식은 뭘까? 라는 고민을 하게 되었고, 이 고민 과정에서 어떻게 현재의 OAuth2 로그인 과정이 생겨났는지 Post 를 작성해보고자 한다.

Discord OAuth2 를 진행하는 과정


카카오 테크 캠퍼스에서 카카오 OAuth2 를 진행해본 경험이 있기에, Discord Login 과정을 단순하게 짚고 넘어가보려고 한다.

  1. Login 버튼을 누름
  2. Discord Redirect URL 로 빠짐
  3. 수락 후, Code 를 Server 에게 반환
  4. 반환 후, Code 를 이용해 AccessToken, RefreshToken 을 반환 및 가져와서 Discord 에 저장되어 있는 User 정보를 가져옴
  5. 해당 정보를 GAMERS 서버에 저장 후, GAMERS 서비스를 이용할 수 있도록 Token 정보를 반환해준다.

위의 과정대로 설정을 하였을 때, 문제는 따로 없다고 생각했다.

하지만 Gemini 의 Code Review 를 받고난 후, CSRF 의 취약점이 발견되었다고 하여서 왜 이런 Review 가 나올 수 있었지? 에 대한 궁금증이 생겨났다.

CSRF 가능성


왜 나의 Code 가 CSRF 공격을 받을 가능성이 있는건가? 하여 검토를 받아보았을 때, Discord Login 을 하려고 하는 요청을 다른 User 에게 넘겨줄 가능성이 있다는 것이었다.

아래의 그림을 보고 설명하고자 한다.

Discord OAuth2 가 Web Server 라고 생각해주세요 ;-;

Discord OAuth2 가 Web Server 라고 생각해주세요 ;-;

우선 Hacker 가 Discord OAuth2 를 통해서 Login 을 시도하려고 한다.

이때 Discord OAuth2 는 Redirect URL 을 전달하고, OAuth2 Login 을 시도하고 성공을 할 시, code=? 라는 query parameter 를 가진 redirect url 이 온다.

해당 url 을 다른 User ( B ) 에게 전달을 한 후, 받은 User ( B ) 는 해당 code 를 통해 website 에 들어갈 경우, 받은 User ( B ) 의 Session 을 Hacker 가 가질 수 있게 된다.

이렇게 될 경우, B 의 계정에 Hacker 가 접근할 수 있는 권한을 가지게 되어버리는 것..

따라서 이를 어떻게 극복할거냐? 라는 질문에 State 를 적용하기로 하였다.

State 는 뭔데?


위의 공격이 성공하는 근본적인 이유는 Login 을 시도하는 주체 ( A ) 와 Login 성공 후 Code 를 받는 주체 ( B ) 가 다르기 때문이다.

따라서 A 와 B 가 같은 사람이게 하기 위해서 State 를 설정하는 것이다.

State 를 Server 에서 발급한 후, Browser 에 Cookie 혹은 Session 으로 저장을 한다.

이때 Redirect URL 에도 State 를 Query Parameter 에 설정하여 Redirect 를 한다.

로그인에 성공을 하면 Code 와 함께 State 또한 같이 오게 되는데, 이때 Browser 에도 쿠키가 있는지 확인하게 된다!

만약 Login 을 시도했던 주체 ( A ) 이면, State 가 일치하니 로그인이 성공하게 될 것이고, Login 을 시도했던 주체가 아니면 State 가 불일치하므로 로그인이 되지 않을 것이다.

OAuth2 과정

이렇게 Discord OAuth2 에 대한 기능 Feature 를 완성할 수 있었다.

추가적으로 Frontend 에서는 Login 후, Discord API ( 외부 API ) 에 정보를 요청하는 부분이 있기에 아래와 같이 Suspense 처리를 해주었다.

suspense

TIP

State 를 제작하는 부분은 Go언어의 crypto/rand 패키지를 사용하여 제작하였다.

만약 여기에서 Discord Login 을 거부하게 된다면?


나는 위의 과정만으로도 충분하겠지! 라는 생각으로 Test 버젼 Release 를 했지만, 지인 중 한 명이 Discord Login 을 취소한 상황이 생기게 되었다.

이때 아래와 같은 화면이 표기된다.

login cancel

Discord OAuth2 가 실패했을 때를 대비하여 처리를 해놓지 않았기 때문이다.

따라서 URL 을 분석해보았을 때, error=? 와 같이 query parameter 가 제출되는 것을 확인하고, controller 에서 Error 처리를 할 수 있는 API Endpoint 까지 설정해주었다.

위의 대응을 통해서 Discord OAuth2 과정에서 로그인 취소 과정에 대해 대응할 수 있게 되었다.

Conclusion


“OAuth2 를 단순히 외부 서비스를 이용해서 나의 서비스에 로그인을 시킨다” 라는 마인드로 접근했다가 굉장히 힘에 겨운 경험을 하였다.

일본인 친구들이 Test 를 꼼꼼하게 도와줘서, 서비스 내에 있는 문제점에 대해 처리할 수 있었다.

하지만 이렇게 Tester 를 도입해서 서비스의 문제점을 찾아내는 것 또한 한계점이 있다고 생각하여, 추후에는 정교한 Test 코드를 통해서 처리할 수 있게 노력하고자 한다.

Reference


Released under the MIT License.