OAuth2.0, OpenID Connect 까지 토끼굴 파기(시퀀스 다이어그램)

dev_dam·2024년 3월 28일
11

토끼굴

목록 보기
2/3
post-thumbnail
post-custom-banner

들어가며

이번 블로그는 OAuth2 프로토콜의 인증과 인가 과정에 대해 시퀀스 다이어그램으로 작성해 보며 이해해 보기 위해 공부하다가 OAuth2의 등장 이전에는 어떤 식으로 인증과 인가를 진행했는지까지 함께 살펴본 내용을 간략히 정리했습니다.
또한 OAuth2.0을 로그인에 접목해서 클라이언트를 프런트와 백엔드로 구분하여 플로우를 시각화해보고 싶어서 시퀀스 다이어그램을 작성한 내용입니다.
시퀀스 다이어그램의 내용은 백엔드 uncle.ra님의 도움을 받았고, 실제 회사의 상황에 따라 플로우는 상이할 수 있습니다.

빠른 요약

  • 인증이란 사용자의 신원을 검증하는 프로세스를 말하며 인가란 인증 이후의 프로세스로 사용자가 특정 자원에 접근할 수 있는지 권한을 확인하는 절차이다.
  • HTTP는 무상태 프로토콜 특징을 가지기 때문에 유저의 상태를 유지하지 않아서 사용자가 계속 로그인해야하는 번거로움이 발생했고, 이런 특징을 가진 HTTP 위에서 상태를 유지하기 위한 다양한 방법인 쿠키, 웹스토리지, 세션, 토큰방식이 등장했다.
  • OAuth는 사용자가 애플리케이션에 모든 권한을 넘기지 않고 사용자 대신 서비스를 이용할 수 있게 해주는 프로토콜이다.
  • OpenID Connect는 OAuth 2.0 프로토콜을 기반으로 한 인증 계층으로 사용자 인증 및 신원확인에 목적이 있다.
  • OAuth 2.0은 데이터에 대한 접근 권한을 제어하는데 목적이 있고, OpenID Connect는 사용자 인증 및 신원 확인에 목적이 있다는 차이점이 있다.
  • OAuth2.0의 로그인 플로우를 시퀀스 다이어그램으로 클라이언트를 프론트와 백엔드로 구분해서 이해해본다.

1. 인증과 인가

인증이란 사용자의 신원을 검증하는 프로세스를 말하며, 일상생활에서는 회사 출근할때 제출하는 사원증을 예로 들 수 있습니다.
웹상으로 적용하면 로그인 하는 과정을 인증이라고 볼 수 있습니다.
인가는 인증 이후의 프로세스로 인증된 사용자가 특정 자원에 접근할 수 있는지 권한을 확인하는 절차를 말합니다.
일상생활로 예를 들면 내 사원증으로 출입할 수 있는 건물은 13층이며 그 외 층은 출입할 수 없는 것을 말하고, 웹상으로 적용하면 로그인 된 사용자가 게시물을 올리고 수정할 수 있지만, 다른 사람의 게시물은 삭제하거나 수정할 수 없는 것을 말합니다

2. HTTP의 무상태(Stateless) 프로토콜

HTTP 관련 자세한 내용은 다음번 블로그에서 다룰 예정입니다.

HTTP는 초창기에 단순히 문서를 확인하는 용도의 통신으로 사용되었습니다.
그렇기 때문에 클라이언트와 서버의 상태를 지속적으로 연결할 필요가 없는 무상태성의 특징을 가지고 있었습니다.
이러한 무상태성의 특징은 클라이언트가 서버에 요청을 보냈을때 서버는 응답을 하고 연결이 끊어져서 이전 상태를 기억하고 있지 않아, 매번 클라이언트가 인증해야되는 번거로움이 있었습니다.
점차 웹의 사용이 늘어나면서 이런 HTTP의 무상태 특성으로 인해 클라이언트는 웹 사이트를 이용해야 할 때 매번 아이디 패스워드를 입력해서 인증해야 하는 번거로움이 발생했고, 이런 무상태 프로토콜의 특징을 가진 HTTP 위에서 인증과 인가를 유지하기 위해 다양한 방법이 등장했습니다.

3. 인증과 인가를 유지하기 위한 다양한 방법들

3-1. 쿠키(Cookie)

쿠키란 웹사이트가 사용자의 브라우저에 저장하는 작은 데이터 조각을 말합니다.

쿠키의 특징

  • 4KB의 크기 제한
  • 기본적으로 key와 value 형태로 저장
  • 만료 시간 설정 가능
  • HTTP 요청시 따로 설정하지 않아도 자동으로 전달

쿠키의 종류

  • 세션 쿠키 (Session Cookies): 브라우저가 열려 있는 동안에만 유지되며, 브라우저가 닫히면 자동으로 삭제된다. 주로 비로그인 장바구니 등에 사용됩니다
  • 영구 쿠키 (Persistent Cookies): 만료 날짜가 설정되어 있어, 브라우저를 닫아도 계속 남게 되며, 주로 n일동안 다시 보지 않기 모달등에 사용됩니다.

쿠키의 동작 원리

  1. 사용자가 웹사이트에 접속하면 서버는 HTTP 응답 헤더에 Set-Cookie 헤더를 포함시켜 사용자의 브라우저에 저장하도록 요청합니다.
  2. 브라우저는 받은 쿠키를 저장하고, 해당 웹사이트에 다시 접속할 때마다 쿠키 정보를 HTTP 요청 헤더에 포함시켜 서버에 전송합니다.
  3. 서버는 요청된 쿠키 정보를 활용해 사용자를 식별해서 서비스를 제공합니다.

쿠키의 단점

  • 4KB의 작은 용량만 저장 가능
  • HTTP 요청을 할때마다 쿠키가 자동으로 전달됨으로, 쿠키가 필요하지 않는 곳에서도 불필요한 트래픽 양이 증가할 수 있습니다.
  • 쿠키는 클라이언트 측에 보관되며 보안에 취약하기 때문에 보안상 민감한 정보를 저장하면 안됩니다.

쿠키에서 데이터 보안을 강화하기 위한 주요 옵션들

  • HttpOnly : HttpOnly를 설정한 쿠키는 자바스크립트와 같은 클라이언트 사이드 스크립트를 통해 접근할 수 없습니다. 이 옵션은 XSS(크로스 사이트 스크립팅) 공격으로부터 쿠키를 보호할 수 있습니다.
    • 사용 방법 : 서버에서 쿠키 설정시 HttpOnly를 추가합니다. (예 : Set-Cookie: id=a3fWa; HttpOnly )
  • Secure : Secure가 설정되면 클라이언트와 서버 간의 통신이 HTTPS를 통해 암호화될 때만 전송되기 때문에 공개 네트워크를 통한 데이터의 유출을 방지할 수 있습니다.
    • 사용 방법 : 쿠키를 설정할 때 Secure를 추가합니다. (예: Set-Cookie: id=a3fWa; Secure )

3-2. 웹 스토리지(Web Storage)

HTML5에서 데이터를 클라이언트에 저장할 수 있는 웹스토리지 스펙이 추가되었습니다.
웹 애플리케이션의 데이터를 사용자의 브라우저에 저장할 수 있게 해주며, 쿠키보다 더 효율적이고 보안적인 방법을 제공하며, 로컬 스토리지(Local Storage)와 세션 스토리지(Session Storage)로 구분됩니다.

웹스토리지 특징

  • 5MB의 정보 저장 가능
  • 자동으로 서버에 전송되지 않음으로 쿠키의 트래픽 문제를 해결

로컬 스토리지(Local Storage)의 특징

  • 도메인 별 저장이 가능
  • 직접 삭제하지 않으면 영구적으로 데이터가 보관
  • 임시 글 저장, 다크모드 등의 설정에 사용

세션 스토리지 (Session Storage)의 특징

  • 도메인 별, 탭 별로 저장 가능
  • 브라우저나 탭을 닫으면 자동으로 삭제됨
  • 입력 폼 저장하거나 일회성 로그인 및 이전 페이지 저장이나 이전 스크롤 위치등에 사용

웹 스토리지의 단점

  • 만료 기간 설정 불가
  • 브라우저간 공유가 안되기 때문에 다른 브라우저로 접속하거나 데스크탑이나 모바일에서 접속시 다른 데이터를 볼 수 있습니다.
  • 문자열만 저장이 가능함으로 다른 형식의 데이터를 저장하려면 데이터를 문자열로 직렬화하고 다시 역직렬화해야합니다.
    • 예를들어 true 또는 false를 저장할때 로컬스토리지 설정에 따라 null, undefined 또는 빈 문자열처럼 버그가 될 수 있습니다.
  • 로컬 스토리지는 직접 삭제하지 않으면 영구적으로 데이터가 보관됨으로 중요 정보를 저장하면 안됩니다.

3-3. 세션(Session)

세션은 서버가 클라이언트와 상호작용을 유지하기 위해 서버 내에 클라이언트의 상태 정보를 저장하는 방식입니다.
클라이언트가 계정과 비밀번호를 서버에 보내서 로그인 요청을 하고 인증 된 사용자의 정보를 세션 저장소에 저장을 하고, 서버는 sessionID를 발급해서 클라이언트에게 보내줍니다.

세션의 특징

  • 고유한 세션ID를 통해 클라이언트를 식별
  • 사용자의 민감한 정보를 직접 전송하거나 저장할 필요가 없습니다.
  • 세션 정보는 서버 측에서 관리함으로 웹스토리지 보다 안전하다.

세션의 동작원리

  1. 사용자가 웹사이트에 로그인을 하면 서버는 sessionID를 발급해서 웹 브라우저에게 전송합니다.
  2. 브라우저는 발급된 sessionID를 쿠키 형태로 저장하고, 이후 사용자가 서버에 요청을 보낼때마다 쿠키를 통해 sessionID가 서버에 전송됩니다.
  3. 서버는 받은 sessionID를 세션 스토어에의 데이터에서 조회하고 사용자의 로그인 상태를 확인하고 사용자에 대한 정보에 접근할 수 있게 됩니다.
  4. 사용자가 로그아웃을 하거나, 일정 시간동안 활동이 없을 경우 서버는 세션을 종료하고 관련 데이터를 삭제함으로 사용자가 브라우저를 닫는 것만으로는 세션이 종료되지 않을 수 있습니다.

세션의 단점

세션 방식은 민감한 정보를 포함하지 않고, 실제 사용자의 정보는 서버측에 저장됨으로 이전 방식보다 보안이 강화되지만 다중 서버 환경일때 문제가 있습니다.
서버가 여러대 일 때 사용자가 요청을 할때마다 매번 같은 서버로 요청이 가지 않기 때문에 각 서버가 개별적인 세션 저장소를 가지고 있다면, sessionID가 없는 서버에서는 사용자를 식별할 수 없다는 문제가 있습니다.
예를들면 A 저장소에 있는 sessionID를 B 저장소로 요청이 간다면, B는 sessionID가 없기 때문에 사용자를 식별할 수 없다는 단점이 있습니다.

3-4. 토큰 (JWT)

세션의 문제점을 보완하기 위해 세션을 서버에 저장하는 대신 토큰(Token)을 클라이언트 측에 저장하고 서버는 이를 검증하는 방식이 등장했습니다.
Token에는 다양한 종류가 있지만 대표적인 JWT(JSON Web Token) 방식에 대해 설명하겠습니다.
JWT의 특징은 시크릿 키(SecretKey)를 사용하여 JWT 토큰을 만들고 시크릿 키를 사용하여 인증과정을 거치는 방식입니다. JWT 자체는 해독하기 무척 쉽기 때문에 민감한 정보를 담지 않아야 하며, 시크릿키(SecretKey)는 서버에서 관리한다는 특징이 있으며 일반적으로 Access Token의 형태로 사용됩니다.

JWT의 동작 원리

  1. 사용자가 로그인 정보를 입력해서 서버로 요청합니다.
  2. 서버에서 로그인 정보가 맞다면 시크릿키를 이용해서 토큰(JWT)를 발급합니다.
  3. 발급한 토큰을 헤더에 실어서 클라이언트(브라우저)에게 보냅니다.
  4. 브라우저는 쿠키 또는 웹스토리지에 JWT를 저장합니다.
  5. 다시 사용자가 서버에 요청을 할 때 저장된 JWT를 HTTP 요청의 Authorization 헤더에 추가하여 서버에 전송합니다.
  6. 서버는 전달받은 JWT를 시크릿키를 사용하여 유효성 검사를 하여 사용자 정보를 파악합니다.

JWT 장점과 단점

JWT 상태를 서버에 저장하지 않고 사용자의 인증을 유지하게 함으로 서버의 부하를 줄이고 확장성을 높입니다.
하지만, 만료 기간을 반드시 설정해야 하는데 만료 시간이 없다면 영구적으로 유효한 상태가 되어 보안에 취약해집니다. 그리고 시크릿 키(SecretKey)를 탈취당하지 않도록 안전하게 보관해야 합니다.

4. OAuth와 OpenID Connect

4-1. OAuth의 등장 배경

사용자 입장에서는 처음 보는 웹사이트에 개인 정보를 맡긴다는 것은 불안합니다.
웹사이트 입장에서도 사용자의 민감한 개인정보를 직접 보관하게 되면 해커에게 탈취된다면 회사 문을 닫아야 할 수 있음으로 직접 관리한다는 것은 부담되는 부분입니다.
이러한 문제들을 해결하기 위해서 OAuth가 등장했습니다.
OAuth란, 사용자가 애플리케이션에게 모든 권한을 넘기지 않고 사용자 대신 서비스를 이용할 수 있게 해주는 프로토콜을 말합니다.
즉, 사용자가 비밀번호를 제공하지 않고 OAuth(서비스 제공 업체)에 사용자의 정보에 대한 권한을 부여하는 방법을 말합니다.
사용자 입장에서는 처음 보는 웹사이트에 ID/PW를 제공하지 않고 OAuth(구글, 페이스북, 카카오, 네이버) 등에 인증하게 돼서 안전하게 사용할 수 있고 웹사이트 입장에서도 사용자의 민감한 개인정보를 직접 보관하지 않고 OAuth에게 사용자의 인증과 인가를 위임받아 사용할 수 있게 되는 장점이 있습니다.
현재 많이 사용되고 있는 OAuth 프로토콜은 OAuth2.0 입니다.
OAuth1.0 프로토콜이 등장했을 당시, 여러가지 단점이 있었고 그 보안된 버전이 OAuth2.0입니다.

OAuth 1.0의 단점

  • Scope 개념 없음
  • Client 구현 복잡
  • 역할이 정확히 나누어지지 않았음
  • 사용 환경 제한적

OAuth 2.0

  • Resource Owner : 사용자
  • Client : 어플리케이션
  • Authorization Server : 클라이언트에게 액세스 토큰을 발급하고, 이 토큰을 사용하여 리소스 서버에 접근할 수 있는 권한을 부여하는 서버
  • Resource Server : 보호된 사용자 데이터를 호스팅하는 서버로, 클라이언트가 제공한 액세스 토큰을 사용하여 리소스에 접근하는 서버

OAuth 2.0 특징

  • Scope 기능 추가 : OAuth 1.0 에서는 토큰이 있으면 모든 권한을 사용할 수 있었음으로 구글 캘린더만 권한을 허용하고 싶었지만, 구글의 모든 제공 기능에 대한 접근권한이 있었습니다.
  • Client 복잡성 간소화 : OAuth 1.0 에서는 암호학적 보안책들을 사용해야 해서 복잡성이 있었지만 이런 복잡성을 Bearer Token과 TLS를 사용하여 간소화 시켰습니다.
  • OAuth 서버의 역할 : OAuth 1.0 에서는 서버의 역할이 정확히 분리되지 않았지만 OAuth 2.0에서는 서버의 역할이 분리되어 인증 서버(Authorization Server) 와 리소스 서버(Resource Server)로 역할이 분리되었습니다.

로그인으로 살펴보는 OAuth2 기본 동작 원리

  1. 사용자(Resource Owner)가 사이트(Client)에 회원가입하기 위해 OAuth2(구글,카카오,네이버등)에 로그인 요청을 합니다.
    1. 사용자가 OAuth에 Authorization code를 요청하는 단계
  2. OAuth2는 사용자가 입력한 정보가 맞는지 확인하고 Redirect URIAuthorization code를 전달합니다.
    1. 사전에 클라이언트는 OAuth2에 ClientID, Client Secret, 인증 성공시 돌아올 화면인 Redirect URI를 OAuth2에 등록해줘야 합니다.
  3. Client는 OAuth2에서 받은 Authorization codeClient의 서버에 전달해줍니다.
  4. Client의 서버는 전달받은 Authorization code를 확인하고 OAuth에게 Authorization code를 전달하여 Resource를 요청합니다.
  5. OAuth는 전달받은 Authorization code를 확인하고 맞다면 해당 scope를 사용하는 권한인 access token을 발급해줍니다.
  6. OAuth로 받은 access tokenClient 서버는 다시 Client(프론트)에게 전달해줍니다.
  7. Client(프론트)는 사용자에게 로그인된 화면을 제공합니다.

4-2. 시퀀스 다이어그램으로 살펴보는 OAuth2.0

OAuth2의 로그인 기본 동작원리는 살펴봤고, 저는 프런트와 백엔드로 나누어져서 실제 업무에 활용할 수 있는 플로우를 파악하고 싶었습니다.
실제로 업무에 사용할 때는 Refresh Token이 필요하며, Access Token의 만료 이후의 플로우도 다이어그램으로 한눈에 파악하고 싶어져서 시퀀스 다이어그램을 그려보기로 했습니다.

Access Token의 유효기간은 짧기 때문에, Refresh Token이 없다면 사용자는 Access Token의 짧은 유효기간이 지나면 계속 로그인을 해야 하는 상황이 발생합니다.

OAuth2 로그인 과정

실제 개발시와 차이가 있을 수 있습니다.

OAuth2 Refresh Token으로 Access Token 갱신 과정

4-3. OpenID Connect

OpenID Connect는 OAuth 2.0 프로토콜을 기반으로 한 인증 계층입니다. 사용자 인증을 위한 표준 프로토콜로, 웹, 모바일, 그리고 다른 서버 사이드 클라이언트 애플리케이션을 위해 설계되었습니다.
OAuth2.0으로 인증을 할 수 있는데 OpenID Connect가 등장한 이유는 OAuth와 OpenID Connect의 사용목적이 다르기 때문입니다.

OAuth 2.0 과 OpenID Connect 의 사용 목적

  • OAuth 2.0 : 리소스 소유자의 데이터에 대한 접근 권한을 제어하는데 중점
  • OpenID Connect : 이를 확장하여 사용자 인증 및 신원 확인에 초점
    즉, OAuth2.0은 사용자의 접근 권한을 받는데 목적이 있다면, OepnID Connect는 사용자의 인증에 초점이 맞춰져 있습니다.

OAuth 2.0만 사용했을 때와 OAuth 2.0과 OpenID Connect를 같이 사용했을 때의 차이점

OAuth 2.0만 사용했을 때는 통신이 더 일어나게 됩니다.
OAuth 2.0만 사용했을 때

  • 사용자는 OAuth에 로그인해서 Access Token을 부여받습니다.
  • 클라이언트는 다시 이 Access Token을 사용하여 리소스 서버에 접근해 사용자의 정보를 받아옵니다.

OpenID Connect를 추가로 사용할 때

  • 클라이언트는 사용자를 인증서버로 요청할때 권한 부여와 사용자 인증을 동시에 함으로 Access Token요청과 OpenID ConnectID 토큰을 한번에 인증 요청합니다.
  • 인증 서버는 클라이언트에게 한번에 Access TokenID 토큰을 보내주기 때문에 서버 통신이 줄어듭니다.

사실, 아까의 다이어그램에서는 백엔드에서 사용자의 정보를 가져오기 위한 플로우가 더 추가되어야 합니다. (다이어그램이 너무 길어져서 뺐습니다)
이렇게 OAuth 2.0만 사용하는 경우, 클라이언트는 사용자를 대신하여 리소스에 접근할 수 있는 권한만 부여받게 됩니다.
하지만 OpenID Connect를 추가로 사용하는 경우, 클라이언트는 사용자의 신원을 확인할 수 있는 ID 토큰을 추가로 받게 되며 이를 통해 사용자 인증 정보를 얻을 수 있게 됩니다.

마무리

여기까지 인증과 인가로부터 시작하여 OAuth2, OpenID Connect까지 토끼굴을 파봤습니다.
OAuth2를 시퀀스 다이어그램으로 작성해 보면서 로그인의 과정 하나도 이렇게 복잡한 절차를 지닌다는 것을 다시금 깨달을 수 있었습니다.
또한, 저는 프런트엔드 개발자이어서 이전에는 항상 프런트 쪽 코드만 관심 갖고 백엔드에 대해서는 크게 관심을 갖지 않았습니다. 하지만 이번에 백엔드의 플로우까지 같이 살펴보고 나니 훨씬 이해하기 좋았고 한층 더 성장할 수 있었던 계기가 되었습니다.

Reference

profile
병아리에서 닭이 될 때까지
post-custom-banner

0개의 댓글