앱과 Spring의 Oauth2

이준우·2024년 7월 8일

Memetory

목록 보기
1/5

웹과 서버의 Oauth2 과정

PAYCO의 OAuth 2.0 인증 과정

해당 과정을 통해서 우리 서버가 PAYCO의 Access Token을 소유하게 된다.

우리 서버는 PAYCO의 Access Token을 통해서 사용자 정보를 가져와서, 우리 서비스의 회원인지 확인하는 절차를 가진다.

즉, 웹과 서버의 Oauth2 로그인 과정에서는 서버가 Resource Server인 PAYCO의 Access Token을 소유함으로써 사용자 인증 절차를 진행하게 된다.

앱과 우리 서버의 Oauth2

나는 백엔드 개발자로서 여태까지 웹이랑만 Oauth2를 진행해왔다. 따라서 앱도 그냥 웹이랑 하던 방식으로 똑같이 Oauth2 로그인을 진행하면 될 줄 알았다.

하지만 앱과의 Oauth2는 웹과의 Oauth2 로그인과 달리 고려할 것이 있었다. 바로 리소스 서버에서 지원해주는 SDK의 사용 여부였다.

SDK를 사용하지 않을 경우

image1 image2

해당 사진은 D-ID 앱에서 로그인을 진행할 때 앱 자체에서 웹 뷰 브라우저를 띄워서 로그인을 진행하는 방법이다.

해당 방식을 사용하면 우리 서버는 웹과 동일한 방식의 구현을 통해서 앱에도 Oauth2 로그인을 적용할 수 있게된다.

사용자의 경우 SDK를 통해서 자동 로그인을 진행할 수 없다는 점에서 불편할 수 있다.

서버 개발자의 경우는 한 번 구현해 두면 웹, 앱 둘 다 같은 방식으로 로그인을 진행할 수 있기 때문에 추가 구현할 필요가 없어진다.

앱 개발자의 경우에는 웹 뷰 브라우저를 통해서 로그인을 진행해야 하기 때문에 웹뷰를 통해서 정보를 받아오는 과정이 복잡해지고 SDK를 통해서 지원되는 라이브러리를 활용할 수 없다는 단점이 존재한다.

SDK를 활용하는 경우

Image 1 Image 2

해당 사진은 화해 앱으로 네이버 SDK를 통한 로그인 방식이다.
네이버 로그인을 선택하게 되면 사용자 휴대폰에 설치되어있는 네이버 앱으로 이동하여 로그인 하는 방식이다.

사용자의 경우 스마트폰에 설치되어있고 로그인 되어있는 앱 중 하나를 선택하여 로그인을 진행하면 되기 때문에 사용하기 편하다.

개발자의 경우 두 가지 중 선택을 해야 한다.

  1. SDK를 통해서 얻은 리소스 서버의 Access Token을 서버로 전송하기
  2. SDK를 통해서 얻은 사용자 정보를 서버로 전송하기

위 두가지 방법중 리소스 서버가 선호하는 방식은 1번이다. 그 이유는 보안이다.

만약 리소스 서버의 사용자의 Access Token을 우리 서버로 전송하는 도중 탈취하는 문제가 발생한다면, 탈취자는 Access Token을 통해서 리소스 서버에 저장되어 있는 사용자에 대한 정보를 모두 사용할 수 있게 된다. 따라서 원칙은 사용자 정보를 격리된 장소에서 보관하면서 필요한 경우에만 리소스 서버로 전송하여 사용하는 것이다. 하지만 꼭 네트워크를 이용해야 할 경우는 SSL이 적용된 HTTPS를 활용하는 것이 좋다.

SDK를 통해서 얻은 사용자 정보를 우리 서버로 전송하기

  1. 앱에서 SDK를 통해서 인증서버의 Access Token을 발급 받는다.
  2. SDK는 Access Token을 통해서 사용자 정보(social_idsocial_type)을 받아온다.
  3. 사용자 정보를 우리 서버로 전달하면, 우리 서버의 내부 DB를 조회해 확인한다.
    1. 신규가입이면 회원가입창으로 Redirection
    2. 기존회원이면 access_tokenrefresh_token을 발급

위 과정에는 보안에 대한 문제점이 존재한다. 바로 로그인에 발급받은 사용자 정보인 social_idsocial_type 에 의존한다는 점이다. social_id는 Oauth2를 진행하는 서비스라면 모두 알 수 있는 정보다. 만약 공격자가 가짜 사이트를 만들어서 사용자의 social_id를 탈취한 후 우리 서비스로 로그인을 진행한다면 우리 서버는 공격자를 사용자로 인식하여 우리 서비스에 대한 인증을 내주게 될 것이다.

위 보안 문제를 어떻게 해결할 수 있을까? 우리 서비스에서 로그인 토큰을 내 주는 방식이다.

로그인 토큰을 활용한 로그인 방식

  1. 앱에서 로그인을 시작하면서 서버에 LoginTokenGET 요청을 통해서 전송
  2. 사용자는 LoginToken을 앱으로 전송
  3. 앱은 OAuth2 로그인을 통해 사용자 정보를 불러옴
  4. 사용자 정보를 불러온 이후 LoginRequest를 통해서 전송
  • DB에 사용자가 없을 경우
    1. 서버는 사용자가 없다는 Trigger 를 앱으로 전달
    2. Trigger 를 받은 앱은 추가 정보를 담아서
      CreateAccountRequest 로 회원가입을 요청
  • 최종적으로 Token 정보를 담은 Response를 반환
  • 앱은 위 과정을 하나의 기능으로 처리한다.

Body

  • LoginRequest
    {
    	"LoginToken" : " ",
    	"socialId" : "Id",
    	"socialType" : "socialType"
    ]
  • CreateAccountRequest
    {
    	"LoginToken" : " ",
    	"socialId" : "Id",
    	"socialType" : "socialType",
    	"name" : "name",
    	"imageUrl" : "imageUrl",
    	"email" : "email" -> 결정난 부분은 아님
    ]
  • LoginToken
    • JWT를 통해 1회용 토큰을 만드는게 베스트 이지만, 1회용 토큰으로 만들기엔 추가적인 비용이 들어간다
      • 블랙리스트 구현과 같은 DB연결을 요함
    • 따라서 1~3분 정도의 유효기간을 둬서 로그인에 한정적으로 사용할 수 있게 구현할 예정이다.
      • 네트워크 전송 + 앱 에서 Oauth2 전송 + 회원가입 등의 이유로 넉넉 잡아 5분으로 했다

현실

현재 진행중인 Memetory 프로젝트에서 앱 개발자와 함께 위 방식들에 장단점들과 지향에야 하는 방식에 대해 알려준 후 어떤 방식으로 로그인을 진행할 것인지 토론을 하였다.

우리 프로젝트의 규모가 크지도 않고, 시간도 많이 남은 것이 아니었기 때문에 우리 팀은 1번 방법인 “SDK를 통해서 얻은 리소스 서버의 Access Token을 서버로 전송하기”를 사용하기로 했다.

로그인 구현이 끝난 지금 시점에서는 정말 아쉬운 선택이었다. 개발자가 편하고자 사용자의 보안을 포기한 상황이기 때문이다. 결국 앱을 사용하는 것은 우리 개발자가 아닌 사용자다. 우리는 좀 더 사용자 관점과 사용자의 정보를 중요시하면서 개발할 필요가 있다.


Reference

안드로이드 카카오 로그인 백엔드 협업 과정에서 궁금한 점이 있습니다

Ios와 서버를 연동해서 카카오 로그인을 진행하려고 합니다

profile
잘 살고 싶은 사람

0개의 댓글