이번 블로그는 OAuth2 프로토콜의 인증과 인가 과정에 대해 시퀀스 다이어그램으로 작성해 보며 이해해 보기 위해 공부하다가 OAuth2의 등장 이전에는 어떤 식으로 인증과 인가를 진행했는지까지 함께 살펴본 내용을 간략히 정리했습니다.
또한 OAuth2.0을 로그인에 접목해서 클라이언트를 프런트와 백엔드로 구분하여 플로우를 시각화해보고 싶어서 시퀀스 다이어그램을 작성한 내용입니다.
시퀀스 다이어그램의 내용은 백엔드 uncle.ra님의 도움을 받았고, 실제 회사의 상황에 따라 플로우는 상이할 수 있습니다.
인증이란 사용자의 신원을 검증하는 프로세스를 말하며, 일상생활에서는 회사 출근할때 제출하는 사원증을 예로 들 수 있습니다.
웹상으로 적용하면 로그인 하는 과정을 인증이라고 볼 수 있습니다.
인가는 인증 이후의 프로세스로 인증된 사용자가 특정 자원에 접근할 수 있는지 권한을 확인하는 절차를 말합니다.
일상생활로 예를 들면 내 사원증으로 출입할 수 있는 건물은 13층이며 그 외 층은 출입할 수 없는 것을 말하고, 웹상으로 적용하면 로그인 된 사용자가 게시물을 올리고 수정할 수 있지만, 다른 사람의 게시물은 삭제하거나 수정할 수 없는 것을 말합니다
HTTP 관련 자세한 내용은 다음번 블로그에서 다룰 예정입니다.
HTTP는 초창기에 단순히 문서를 확인하는 용도의 통신으로 사용되었습니다.
그렇기 때문에 클라이언트와 서버의 상태를 지속적으로 연결할 필요가 없는 무상태성의 특징을 가지고 있었습니다.
이러한 무상태성의 특징은 클라이언트가 서버에 요청을 보냈을때 서버는 응답을 하고 연결이 끊어져서 이전 상태를 기억하고 있지 않아, 매번 클라이언트가 인증해야되는 번거로움이 있었습니다.
점차 웹의 사용이 늘어나면서 이런 HTTP의 무상태 특성으로 인해 클라이언트는 웹 사이트를 이용해야 할 때 매번 아이디 패스워드를 입력해서 인증해야 하는 번거로움이 발생했고, 이런 무상태 프로토콜의 특징을 가진 HTTP 위에서 인증과 인가를 유지하기 위해 다양한 방법이 등장했습니다.
쿠키란 웹사이트가 사용자의 브라우저에 저장하는 작은 데이터 조각을 말합니다.
Set-Cookie
헤더를 포함시켜 사용자의 브라우저에 저장하도록 요청합니다.Set-Cookie: id=a3fWa; HttpOnly
)Set-Cookie: id=a3fWa; Secure
)HTML5에서 데이터를 클라이언트에 저장할 수 있는 웹스토리지 스펙이 추가되었습니다.
웹 애플리케이션의 데이터를 사용자의 브라우저에 저장할 수 있게 해주며, 쿠키보다 더 효율적이고 보안적인 방법을 제공하며, 로컬 스토리지(Local Storage)와 세션 스토리지(Session Storage)로 구분됩니다.
세션은 서버가 클라이언트와 상호작용을 유지하기 위해 서버 내에 클라이언트의 상태 정보를 저장하는 방식입니다.
클라이언트가 계정과 비밀번호를 서버에 보내서 로그인 요청을 하고 인증 된 사용자의 정보를 세션 저장소에 저장을 하고, 서버는 sessionID
를 발급해서 클라이언트에게 보내줍니다.
sessionID
를 발급해서 웹 브라우저에게 전송합니다. sessionID
를 쿠키 형태로 저장하고, 이후 사용자가 서버에 요청을 보낼때마다 쿠키를 통해 sessionID
가 서버에 전송됩니다.sessionID
를 세션 스토어에의 데이터에서 조회하고 사용자의 로그인 상태를 확인하고 사용자에 대한 정보에 접근할 수 있게 됩니다.세션 방식은 민감한 정보를 포함하지 않고, 실제 사용자의 정보는 서버측에 저장됨으로 이전 방식보다 보안이 강화되지만 다중 서버 환경일때 문제가 있습니다.
서버가 여러대 일 때 사용자가 요청을 할때마다 매번 같은 서버로 요청이 가지 않기 때문에 각 서버가 개별적인 세션 저장소를 가지고 있다면, sessionID
가 없는 서버에서는 사용자를 식별할 수 없다는 문제가 있습니다.
예를들면 A 저장소에 있는 sessionID
를 B 저장소로 요청이 간다면, B는 sessionID
가 없기 때문에 사용자를 식별할 수 없다는 단점이 있습니다.
세션의 문제점을 보완하기 위해 세션을 서버에 저장하는 대신 토큰(Token)을 클라이언트 측에 저장하고 서버는 이를 검증하는 방식이 등장했습니다.
Token에는 다양한 종류가 있지만 대표적인 JWT(JSON Web Token) 방식에 대해 설명하겠습니다.
JWT의 특징은 시크릿 키(SecretKey)를 사용하여 JWT 토큰을 만들고 시크릿 키를 사용하여 인증과정을 거치는 방식입니다. JWT 자체는 해독하기 무척 쉽기 때문에 민감한 정보를 담지 않아야 하며, 시크릿키(SecretKey)는 서버에서 관리한다는 특징이 있으며 일반적으로 Access Token
의 형태로 사용됩니다.
Authorization 헤더
에 추가하여 서버에 전송합니다.JWT 상태를 서버에 저장하지 않고 사용자의 인증을 유지하게 함으로 서버의 부하를 줄이고 확장성을 높입니다.
하지만, 만료 기간을 반드시 설정해야 하는데 만료 시간이 없다면 영구적으로 유효한 상태가 되어 보안에 취약해집니다. 그리고 시크릿 키(SecretKey)를 탈취당하지 않도록 안전하게 보관해야 합니다.
사용자 입장에서는 처음 보는 웹사이트에 개인 정보를 맡긴다는 것은 불안합니다.
웹사이트 입장에서도 사용자의 민감한 개인정보를 직접 보관하게 되면 해커에게 탈취된다면 회사 문을 닫아야 할 수 있음으로 직접 관리한다는 것은 부담되는 부분입니다.
이러한 문제들을 해결하기 위해서 OAuth가 등장했습니다.
OAuth란, 사용자가 애플리케이션에게 모든 권한을 넘기지 않고 사용자 대신 서비스를 이용할 수 있게 해주는 프로토콜을 말합니다.
즉, 사용자가 비밀번호를 제공하지 않고 OAuth(서비스 제공 업체)에 사용자의 정보에 대한 권한을 부여하는 방법을 말합니다.
사용자 입장에서는 처음 보는 웹사이트에 ID/PW를 제공하지 않고 OAuth(구글, 페이스북, 카카오, 네이버) 등에 인증하게 돼서 안전하게 사용할 수 있고 웹사이트 입장에서도 사용자의 민감한 개인정보를 직접 보관하지 않고 OAuth에게 사용자의 인증과 인가를 위임받아 사용할 수 있게 되는 장점이 있습니다.
현재 많이 사용되고 있는 OAuth 프로토콜은 OAuth2.0 입니다.
OAuth1.0 프로토콜이 등장했을 당시, 여러가지 단점이 있었고 그 보안된 버전이 OAuth2.0입니다.
Bearer Token
과 TLS를 사용하여 간소화 시켰습니다.Redirect URI
로 Authorization code
를 전달합니다.Authorization code
를 Client의 서버에 전달해줍니다.Authorization code
를 확인하고 OAuth
에게 Authorization code
를 전달하여 Resource를 요청합니다.Authorization code
를 확인하고 맞다면 해당 scope
를 사용하는 권한인 access token
을 발급해줍니다.access token
을 Client 서버는 다시 Client(프론트)에게 전달해줍니다.OAuth2의 로그인 기본 동작원리는 살펴봤고, 저는 프런트와 백엔드로 나누어져서 실제 업무에 활용할 수 있는 플로우를 파악하고 싶었습니다.
실제로 업무에 사용할 때는 Refresh Token이 필요하며, Access Token의 만료 이후의 플로우도 다이어그램으로 한눈에 파악하고 싶어져서 시퀀스 다이어그램을 그려보기로 했습니다.
Access Token의 유효기간은 짧기 때문에, Refresh Token이 없다면 사용자는 Access Token의 짧은 유효기간이 지나면 계속 로그인을 해야 하는 상황이 발생합니다.
실제 개발시와 차이가 있을 수 있습니다.
OpenID Connect는 OAuth 2.0 프로토콜을 기반으로 한 인증 계층입니다. 사용자 인증을 위한 표준 프로토콜로, 웹, 모바일, 그리고 다른 서버 사이드 클라이언트 애플리케이션을 위해 설계되었습니다.
OAuth2.0으로 인증을 할 수 있는데 OpenID Connect가 등장한 이유는 OAuth와 OpenID Connect의 사용목적이 다르기 때문입니다.
OAuth 2.0만 사용했을 때는 통신이 더 일어나게 됩니다.
OAuth 2.0만 사용했을 때
Access Token
을 부여받습니다.Access Token
을 사용하여 리소스 서버에 접근해 사용자의 정보를 받아옵니다.OpenID Connect를 추가로 사용할 때
Access Token
요청과 OpenID Connect
의 ID 토큰
을 한번에 인증 요청합니다.Access Token
과 ID 토큰
을 보내주기 때문에 서버 통신이 줄어듭니다.사실, 아까의 다이어그램에서는 백엔드에서 사용자의 정보를 가져오기 위한 플로우가 더 추가되어야 합니다. (다이어그램이 너무 길어져서 뺐습니다)
이렇게 OAuth 2.0만 사용하는 경우, 클라이언트는 사용자를 대신하여 리소스에 접근할 수 있는 권한만 부여받게 됩니다.
하지만 OpenID Connect를 추가로 사용하는 경우, 클라이언트는 사용자의 신원을 확인할 수 있는 ID 토큰을 추가로 받게 되며 이를 통해 사용자 인증 정보를 얻을 수 있게 됩니다.
여기까지 인증과 인가로부터 시작하여 OAuth2, OpenID Connect까지 토끼굴을 파봤습니다.
OAuth2를 시퀀스 다이어그램으로 작성해 보면서 로그인의 과정 하나도 이렇게 복잡한 절차를 지닌다는 것을 다시금 깨달을 수 있었습니다.
또한, 저는 프런트엔드 개발자이어서 이전에는 항상 프런트 쪽 코드만 관심 갖고 백엔드에 대해서는 크게 관심을 갖지 않았습니다. 하지만 이번에 백엔드의 플로우까지 같이 살펴보고 나니 훨씬 이해하기 좋았고 한층 더 성장할 수 있었던 계기가 되었습니다.