이번 기수부터 생긴 코테이토의 백엔드 네트워킹 시간. 우리 Team의 첫 주제는 OAuth와 OIDC이다.
아래 Flow의 문제점을 찾고 OIDC로 해결해보는게 첫 과제였다.
1. 가능한 OAuth2.0의 Flow
위 4가지 과정이 무엇을 하는지 정리해보자.
- 로그인 하지 않은 상태.
새로운 웹서비스 코테이토에 로그인하려하는데, 현재 로그인이 되어있지 않은 상태이다. 로그인 버튼을 눌러 OAuth로 로그인을 시도해보자. - 카카오(소셜로그인) 동의여기서는 생일, 카카오계정(이메일), 출생년도, 성별, 연계정보, 카카오계정(전화번호)를 받아와도 되는지 허가 받고 있다.
카카오에서 해당 회원의 정보를 받아오려는데 user의 정보를 받아와도 되는지 확인하는 과정이다. - cotato 서비스 회원 가입 약관동의이때, 다른 과정처럼 user에게 따로, 회원정보를 입력받지 않고 있다.
(이미 받았으니까!!!) - 카카오 서버에서 필요한 정보(2번째 단계에서 동의받은)를 받아왔다. 이 정보를 가지고 회원가입을 하려고 해당 Cotato 서비스에 대한 약관동의를 받고 있다.
- 회원 가입 및 로그인 완료
회원이 약관 동의를 받은 이후, 회원가입을 진행했고 로그인 이후의 화면으로 넘어갔다. (회원 가입 및 로그인 성공)
이 과정의 Flow를 그림으로 정리해보자.
그림 정리
여기서 언급하는 용어 정리 먼저하겠다.
- Client: 사용자가 아닌, 카카오에 정보를 요청하는 제 3자 어플리케이션 (여기서는 cotato 어플이다.
- Resource Owner: 정보의 실 소유자, 해당 서비스를 이용하는 User를 의미한다.
- Authorization Server: 정보를 가지고 있는 플랫폼(카카오)에서 정보를 요청한 회원 Authorize(인가)를 관리하는 서버 여기에는 2가지 Endpoint가 있다.
- Authorization Endpoint: 정보를 요청한 User가 진짜 User인지, Resource Owner인지를 확인하고 확인 했으면 Authorzation code를 발급한다.
- Authorization Code: 해당 코드를 통해 Access Token을 발급 받을 수 있는 Token Endpoint로 이동할 수 있다.
- Token Endpoint: 실질적인 Token을 발급해주는 지점.
- Resource Server: 필요한 실제 User의 정보를 저장해놓은 서버.
이제, Flow를 정리한 그림을 보자.
- User가 새로운 어플리케이션에 로그인이 되어있지 않은 상태에서 소셜 로그인을 시도한다.
- Client는 Authorization Server에 User의 요청을 전달한다.
(GET: /oauth/authorize) - Resource Server는 Resource Owner를 인증하기 위해 로그인 요청과 같은 인증 요청을 한다.
- Resource Owner는 Resource 서버에 로그인과 같은 방식으로 본인을 인증을 한다.
- Authorization Server의 Authorization Endpoint에서 이 권한 확인하고 확인에 성공했으면 개인정보 제공 동의를 Resource Owner에 전달한다.
- Client는 필요한 개인정보 동의서를 작성해 Authorization Server로 보낸다.
동의항목: 생일, 카카오계정(이메일), 출생년도, 성별, 연계정보, 카카오계정(전화번호) - 인증과 인가 완료 후 Authorization Server는 Client에게 Access Token을 받을 수 있는 Authorization code(인가코드)를 전달한다.
- Client는 Token Endpoint에 Access Token을 요청한다.
- Authorization Server의 Token Endpoint에서 Access Token을 발급해준다.
- Client는 이 Access Token을 통해 Resource Server에 필요한 User Resource를 요청한다.
- Resource Server는 Access Token의 유효성을 확인하고, 확인되면 필요한 Resource를 반환한다.
- 이 정보를 바탕으로 자체적으로 회원가입을 실행한다.
- 우리 서비스에 User를 회원가입 시키기 위한 약관 동의를 구한다.
- User는 동의를 한다.
- 클라이언트는 User를 로그인 이후로 이동시킨다.
❗3~6의 과정은, Resource Owner와 Authorization Server가 직접 통신할 수도 있고 중개자 (Client를 중간에 두고 할 수도 있다.)
2. 나타나는 문제점?
우선, 조금 띠용하는 부분이 있다.
회원가입 → 약관동의 순서의 문제
12,13을 보면 회원가입 → 약관동의가 진행된다. 회원가입에 동의를 하지 않았는데, 이미 자체적으로 회원 가입을 시켰다는 문제가 있다.
user입장에선, 소셜로그인 버튼과 정보제공 동의만 눌렀는데, 회원가입처리가 되어버린 것이다.
순서에 문제가 있다.
Client서버에서 user를 인증하지 않음.
위의 Flow를 보면, 사용자를 인증하는 과정은 카카오 로그인과 같이 소셜 서비스에서 인증을 한 것 외에는 사용자를 인증하지 않는다.
이 사용자가 진짜 사용자가 맞는지 client 서버에선 자체적으로 검증하지 않는 문제가 있다.
소셜 로그인을 통한 회원 가입이라하면, 소셜 서비스에 내가 제공한 ID, Pwd와 같은 정보를 바탕으로 새로운 3자 서비스에 가입하는 과정이다.
즉, Client 서버에도 회원을 인증할 수 있는 정보가 존재해야하고 이를 바탕으로 로그인을 해야한다.
근데, 카카오 서버에서 한 인증으로만, 그 인증에 대한 어떠한 정보도 받지 못했는데 우리 서버에서 회원을 인증시킨다?
Access Token을 통한 인증
그렇다면 Access Token을 통해 사용자의 정보를 받을 수 있으니, 인증을 위한 ID, Pwd까지 받아와서 인증을 해보는 건 어떨까?
우선, 동의항목에 비밀번호가 없다. 자체적인 인증을 위해선, 비밀번호가 필요하니 비밀번호를 카카오에 요청해보자.
이 과정을 그림으로 나타내면 아래와 같다.
위에 진행했던, Flow에 이어서 한번 더 정보를 요청하는 과정을 거쳐야한다.
여기서 두 번째 문제가 발생한다.
요청을 두 번 함에 따라 트래픽이 두 배로 증가하게 되는 문제가 발생!
그렇다면, 이렇게 생각할 수 있다. 처음 요청할 때 비밀번호까지 같이 받아오면 되지 않는가?
그 전에 이상함을 느꼈겠지만, 애초에 Resource 서버에서 절대 노출되면 안될 비밀번호를 제공한다는 것 자체가 말이 안된다.
카카오 개인정보 제공 동의항목을 보면 아래와 같은데 비밀번호는 존재하지 않는다.
https://developers.kakao.com/docs/latest/ko/kakaologin/prerequisite#personal-information
또한, 제공한다고 해도 대부분의 DB에선 Encrypted된 비밀번호만 저장하고 진짜 비밀번호는 저장을 하지 않으니, 비밀번호가 제공되어도 해결될 것은 없다.
왜 이런 문제가 발생할까?
애초에, OAuth2.0 과 Access Token에 대한 정의를 생각해보자.
OAuth를 정의한, RFC6749를 보면, OAuth는 정보 제공에 동의하는 인가(Authorization) 에 관한 프레임워크이지 인증에 대한 이야기는 없다.
또한 Access Token도, 정보를 요청하는데 쓰이는 토큰이지, 인증을 하는데 쓰이는 토큰이 아니다.
- 액세스 토큰은 ID와 같은 유저 식별 정보를 포함하지 않는다.
- 액세스 토큰은 리소스를 요청하는데에만 사용되어야하고, 그 외의 작업은 ID token 을 사용하라.
이렇게 정의하고 있다.
OAuth2.0과 Access Token으로 인증을 다룬다는게 설계의도와 맞지 않기에 이런 문제가 발생하는 것이다.
이러한 문제를 보완하기 위해, OAuth의 확장 프레임워크인 OIDC가 등장했다.
OpenID Connect(OIDC)
OpenID Connect(이하 OIDC)란, OAuth에 인증 의 개념을 얹은 프레임워크이다.
OAuth와 비슷한 Flow로 흘러가지만, Access Token외에도 End point User 인증을 위한 ID Token이 발급된다.
ID Token이란?
ID Token은 Oauth2.0에 End-User를 인증하게하는 OAuth의 확장 버전이라고 공식문서에서 정의하고 있다.
User를 인증하기 위한 Token이다. 이 Token에는 User를 식별할 수 있는 식별정보가 들어가 있는데 JWT 형태로 작성되어있다. (Access Token은 반드시 Jwt 형태일 필요 없음.)
Access Token이 호텔 방키라면, ID Token은 방 주인을 입증하는 주민등록증인셈이다.
ID Token에 포함되는 정보는 아래와 같다.
Header, Payload, Signature로 구성되어 있는데 Payload에 중요한 정보들이 담긴다.
- iss: 토큰을 발행한 발행기관 (카카오와 같은 소셜 서비스)
- aud: ID Token을 발행한 앱의 키 (Client, 여기선 Cotato)
- sub: ID Token이 제공하는 사용자 정보
이렇게 ID Token에는 사용자를 인증한 사용자 정보가 담기는데, 이를 통해 우리의 Flow를 수정하면 다음과 같다.
ID Token으로 카카오에서 이 회원이 인증되었다는 내용을 Jwt로 받고, 이를 복호화한 유저 식별 정보등을 활용해 회원가입을 진행하면 된다.
따라서, ID Token을 통해 user 인증 문제를 해결했다.
추가로, ID Token의 장점을 정리하자면 다음과 같다.
- 상호 운용성
인증 서비스는 다양한 Consumer가 서비스를 사용할 수 있도록 상호 운용성을 충족해야하는데, OIDC를 통해 필요한 사용자의 정보 ID 토큰을 통해 받아올 수 있음 - 단순성, 모바일 지향 형식
Json 기반의 Rest 친화적인 구조로 쉽게 사용가능 - 보안
ISO/IEC 29115 Entity Authentication Assurance 프레임워크 레벨 1~4를 선택할 수 있음. - 유연성
다양한 타입으로 사용이 가능하다.
또 사실 OIDC를 사용하지 않으면 하나의 문제가 더 발생하는데, 이는 다른 페이지에 정리하도록 하겠다. 궁금하면 블로그를 잘 구독하도록!
참고
https://gintrie.tistory.com/38
https://datatracker.ietf.org/doc/html/rfc6749#section-1.2
https://developers.kakao.com/docs/latest/ko/kakaologin/common#oidc-id-token
https://www.samsungsds.com/kr/insights/oidc.html
https://www.oauth.com/oauth2-servers/openid-connect/id-tokens/
https://nordicapis.com/what-is-openid-connect/
'BE > 개발일지' 카테고리의 다른 글
다량의 데이터 삽입 시간 줄이기 (0) | 2024.05.15 |
---|---|
데이터베이스 기본키 생성 전략 (0) | 2024.05.15 |