크로스 도메인간 로그인 연동 (SSO)

@ZungTa · 2022-04-25 월요일 · 3 min read

Intro
Research
SSO with OAuth
Implementation
Implementation - 문제점
Implementation - 2
P.S.

Intro

기존에 A사이트를 운영 중 색다른 기능의 B사이트 프로젝트 개발을 시작했다.

프로젝트의 요구 사항으로 A사이트와 로그인 연동이 필요했다.

이 말은, 아래와 같다.

  • A에서 로그인된 상태로 B 이동 시 로그인 되어있을 것.
  • B에서 로그인된 상태로 A 이동 시 로그인 되어있을 것.

Research

처음엔 A에서 session을 사용중이니까 이 session을 공유하는 방식으로 하려고 했다.

A와 B 둘 다 같은 redis를 session store로 사용하면 같은 유저에 대해 session이 공유되지 않을까? 생각하였다.

하지만 테스트해 본 결과 생각과 달리 같은 client에 대해 각 서버는 각자의 session을 가졌다.

그래서 자료조사를 더 해보고 SAML방식과 OAuth방식으로 SSO(Single Sign On)가 가능하다는 걸 알아냈다.

내 생각에 좀 더 트렌디 하다고 생각되는 OAuth 방식으로 시도했다.

SSO with OAuth

기본적인 OAuth의 Authorization Server를 구축하는 것은 그렇게 복잡하진 않지만

익숙하지 않은 사람이 뚝딱 만들 수 있을 만큼 단순하진 않다.

redirect 를 통해서 사이트를 왔다갔다 하기 때문에 query string에 callback url을 넣는 방식을 쓴다.

Implementation

기본적으로 A에 login이 구현이 되어 있기 때문에 Authentication은 A에 일임하고,

A에 내부적으로 OAuth와 비슷한 형태의 API를 구성했다.

B에서 로그인 할 경우 A의 로그인 페이지로 callback url과 함께 redirect시키고,

로그인이 완료되면 A에서 B의 callback url로 redirect 시켜주는데 이 때 useId를 query string으로 붙여준다.

그럼 사용자의 브라우저에서 B사이트로 userId를 가지고 요청이 되었기 때문에 이제 B에선 userId를 이용하여 유저가 누군지 알고 로그인 처리를 할 수 있다.

Implementation - 문제점

저렇게 구현하면 간단하다. 하지만 문제점이 무엇일까?

유저가 A에서 실제 로그인을 하지 않아도 B에서 로그인을 할 수 있다.

누군가 타인의 userId값을 알고 있거나, 또는 userId값이 숫자라서 아무 숫자나 B의 callback url에 대입하다가 맞아 떨어지면 바로 로그인 처리가 되어버린다.

Implementation - 2

다시 처음부터,

사전에 A와 B사이에 비밀 키(secretKey)를 하나 공유한다.

secretKey의 값은 그냥 문자열로 아무 값으로 해도 된다.

B에서 로그인 할 경우 A의 로그인 페이지로 callback url과 함께 redirect시키고,

로그인이 완료되면 A에서 B의 callback url로 authCode를 query string으로 붙여서 이동시켜준다.

또한 나중에 authCode를 통해 유저의 id를 반환하기 위해서 DB table을 하나 만들어두고 A의 로그인과 함께 auth_codeuserId를 DB에 저장한다. (일회용 데이터이기 때문에 redis같은 곳에 저장해도 상관 없다.)

그럼 이제 B에선 authCode를 가지고 있고 secretKey도 가지고 있다.

이 두가지 정보를 가지고 B에서 A로 직접 API를 요청한다.

그럼 A에선 secretKey의 유효성을 검증하고 authCode로 DB조회 하여 userId를 찾을 수 있고, 그 값을 응답해준다.

그럼 이제 B에선 userId를 알게되었고 로그인 처리를 하고 session이나 JWT로 로그인 처리를 하면 된다.

그림으로 정리하면 이렇다.

SSO with OAuth

SSO with OAuth

P.S.

저 과정은 자유롭게 customizing이 가능할 것 같다.

  • 보안을 좀 더 강화하기 위해 authCode만 확인하는 것이 아니라 사전에 등록된 url에서 온 요청인지도 비교한다
  • 더 간단한 방식으로 secretKeyuserId를 암호화 및 검증해서 DB나 API 통신도 필요 없게 할 수 있다.
  • 실제 OAuth 서비스처럼 secretKey도 API를 통해 등록되게 한다.

등등 여러 방법이 있을 것 같다.

일단 아직까지 저 방식에 문제가 있을 것 같지는 않아서 저렇게 적용하려고 한다.

@ZungTa
I'm a backend developer
© ZungTa Devlog, Built with Gatsby