OAuth 2.0 + JWT + Spring Security로 회원 기능 개발하기 - OAuth 2.0을 선택한 이유

DevSeoRex·2023년 5월 20일
6
post-thumbnail

🙂 회원기능 어떻게 처리하면 좋을까?

2번의 프로젝트를 진행하면서 로그인 & 회원가입 기능을 소셜로그인을 이용해 구현해본적이 있었습니다.
최근에는 OAuth 2.0과 Spring Security를 이용한 인증 & 인가를 구현한 애플리케이션이 굉장히 많아보였습니다.

프로젝트를 2번 진행하는 동안 Spring Security를 사용해본거라고는 오직 PasswordEncoder로 비밀번호를 암호화 한 경험 뿐인데 패기 하나로 도전은 시작되었습니다.

이때까지만 하더라도 이 패기가 엄청난 삽질을 알리는 종소리일줄 몰랐습..

회원 로그인과 회원 가입 기능에 대해서 시나리오를 생각하다가 OAuth 2.0을 이용하기로 결정했습니다.

이유 1 - 민감한 정보 관리로부터의 해방

회원을 자체 회원가입을 통해 가입시키게 되면 두가지의 책임이 서비스 제공자에게 돌아갑니다.
첫번째 책임은 회원이 기입한 아이디와 비밀번호와 같은 회원의 개인정보에 접근할 수 있는 중요 식별정보를 서비스 제공자가 관리해야 하는 책임입니다.

두번째 책임은 회원이 아이디 또는 비밀번호를 해킹당하거나 잃어버렸을때 복구할 수 있는 방법을 제공해줘야하는 책임입니다.

OAuth 2.0을 이용한 회원 서비스를 구축한다면 회원과 관련된 민감한 정보의 관리 책임은 해당 OAuth 2.0 서비스를 제공하는 플랫폼 제공자에게 있습니다.

따라서 첫번째 책임과 두번째 책임을 지지 않아서 개발 생산성이 올라갑니다.

이유 2 - 사용자 경험 증가

자체 회원가입의 경우 입력 받아야 할 정보가 많아, 사용자에게 많은 입력을 요구합니다.
사용자는 서비스를 이용하기 위하여 정보를 입력하는 대신에, 구글과 같은 OAuth 2.0 서비스 제공자가 제공하는 로그인 페이지에서 기존에 사용하던 계정으로 로그인하면 마치 구글에 로그인하듯이 우리 서비스를 자연스럽게 사용할 수 있다는 이점이 생겨, 사용자 경험이 대폭 증가할 것입니다.

😎 OAuth 2.0 너를 알고 싶다!

OAuth 2.0은 무엇일까요? 이름부터가 낯선 이 친구는 어떻게 생기게 되었는지 알아보겠습니다.

우리가 흔히 부르는 오어-th 또는 오어스(OAuth)는 약어입니다.
OAuth의 풀네임은 Open Authorization 입니다. Open Authorization의 정의는 아래와 같습니다.

  • Open Authorization
    • 자신이 소유한 리소스에 소프트웨어 애플리케이션이 접근할 수 있도록 허용해 줌으로써 접근 권한을 위임해주는 개방형 표준 프로토콜

그렇다면 OAuth라는 개념은 왜 등장하게 되었을까요?

한번 예시를 들어보겠습니다.
A라는 사이트가 있고 A라는 사이트 중의 한 서비스는 B사이트의 회원정보가 필요하다고 하겠습니다.
A사이트에서 B사이트의 회원정보에 접근하기 위해서는 아래와 같은 절차를 진행해야 할 것입니다.

  1. A사이트에 가입하는 회원은 B사이트의 아이디 비밀번호를 A사이트에 제공한다.
  2. A사이트는 회원이 제공한 B사이트의 아이디 비밀번호를 이용해 B사이트에서 회원의 정보를 가져온다.

이렇게 보면 말이 되는 것 같습니다. 과연 이렇게 처리하는 것에 문제는 없을까요? 많은 문제들이 있습니다.

신뢰 문제와 보안 위협 문제 발생

만약에 제가 구글 서비스를 이용하기 위해서 구글에 가입하는데 네이버 아이디와 비밀번호를 요구한다면 믿고 넘겨줄 수 있을까요?

여기서 신뢰 문제가 발생합니다.
두번쨰로 제가 네이버 아이디와 비밀번호를 구글에 넘겨줬는데 구글 서버가 해킹당해서 제 네이버 아이디와 비밀번호가 해커의 손에 넘어간다면 이건 누가 책임져야 할까요?

유저가 서비스를 신뢰해서 다른 제공자의 아이디 비밀번호를 알려준다고 하더라도, 다른 사이트의 아이디 비밀번호를 보관하고 있는 해당 서비스는 정보를 안전하게 보관해야 할 의무가 생기게되고 해킹이나 다른 공격으로 인하여 정보가 유출되면 책임으로부터 자유로워질 수 없는 것입니다.

OAuth의 시작

OAuth는 2006년 트위터 개발자와 Gnolia의 개발자가 안전한 인증방식에 대한 논의를 하면서 OAuth가 등장하게 되었고, OAuth 1.0이 2010년에 발표 되었습니다.
OAuth 1.0은 사용자 정보에 접근할 수 있는 토큰의 유효기간이 없고, 세션 고정 공격에 취약점을 가지고 있다는 단점이 있었습니다. 이런 문제를 보완하여 발표된 OAuth 2.0이 현재 많이 사용되고 있습니다.

👉 OAuth 2.0은 하위 버전과 호환되지 않습니다.

OAuth 용어정리

OAuth를 이해하는데 있어서 필요한 용어들을 간단히 정리해보았습니다.

  • Resource Server
    • OAuth2.0 서비스를 제공하고 자원을 관리하는 서버(보통 google, naver 같은 다른 사이트)
  • Resource Owner
    • Resource Server의 계정을 소유하고 있는 사용자
  • Client
    • Resource Server의 API를 사용하여 사용자 데이터를 가져오려고 하는 사이트
  • Authorization Server
    • Client가 Resource Server의 서비스를 사용할 수 있게 인증하고 토큰을 발행해주는 서버(인증 서버, google, naver)
  • Authorization Code
    • 사용자가 로그인에 성공하고 나서 받는 코드 → 액세스 토큰 발급에 필요
  • Access Token
    • 리소스에 접근할 때 필요한 토큰
  • Scope
    • 리소스 접근 범위
  • Redirect URI
    • 인증 서버가 인증 후 응답을 보낼 클라이언트 URI

여기서 약간 혼동되는 개념이 Client입니다.
Client는 요청을 하는 주체가 Client인데 그렇다면 여기서 말하는 Client가 프론트앤드 또는 사용자라고 봐야 하는지라는 궁금함이 생겼었습니다.

정답부터 말씀드리면, 아닙니다.
그 이유는 Resource Server의 입장에서는 우리의 Spring Server가 Client가 됩니다. 프론트앤드를 거쳐서 사용자가 OAuth 2.0 인증을 통해 로그인을 진행하게 되면 Spring Server가 Resource Server에게 로그인된 사용자의 정보를 요청하는 주체가 되기 때문에 Client는 우리의 서비스가 됩니다.

OAuth 2.0은 어떻게 사용자의 정보를 가져올까?


어떤 서비스에서 우리가 소셜 로그인을 이용하려고 하면 이런 화면을 만나게 됩니다.
구글을 예로 들어보겠습니다. 현재 구글 버튼에는 http://localhost/oauth2/authorization/google 링크가 걸려있습니다. 이 링크를 클릭하게되면 구글 로그인 페이지가 사용자에게 보여지게 됩니다.

사용자가 로그인에 성공하면 서버는 사용자의 정보를 이용해서 회원가입을 시키거나 AccessToken을 발급해줍니다.

그렇다면 어떤 과정을 통해서 사용자의 정보를 가져오는지 살펴보겠습니다.

RFC 스펙을 살펴보면 여러가지 GRANT 전략이 있는데, 이중에서 가장 많이 이용되는 Authorization Code Grant 방식을 살펴보겠습니다.

공식 문서는 인증 과정을 아래의 사진을 통해 설명하고 있습니다.

간단히 정리하면 아래와 같이 진행됩니다.
1. 애플리케이션이 OAuth 서버에 요청을 보내, 브라우저(로그인 페이지)가 열리고 사용자가 인증을 진행합니다.
2. 사용자는 브라우저에서 인증을 진행하고, 애플리케이션이 요구하는 권한(정보 제공 동의)을 승인합니다.
3. 사용자는 OAuth 서버에서 인증코드를 받아서 애플리케이션으로 돌아옵니다.
4. 애플리케이션은 인증코드를 accessToken으로 교환해줍니다.

Authorization Code Grant 방식이 많이 사용되는 이유는 뭘까?

accessToken을 얻기 위한 인증 코드를 교환하는 단계가 더 있어서 보안에 유리한 장점이 있습니다.
코드를 교환하는 단계에서 accessToken은 항상 보호된 서버 backchannel(뒷단)에서 애플리케이션과 OAuth 서버를 이동하기 때문에 공격자가 중간에 가로챌 수 없다는 장점도 있습니다.

🤔 Spring Security와 OAuth 2.0의 콜라보 선택이유

Spring Security를 사용하지 않고 OAuth 서버에 요청을 보내서 사용자의 정보를 얻어오려면 2번의 요청을 통해 얻어와야 합니다.

클라이언트 정보와 함께 OAuth 서버에 Get 요청을 보내, accessToken 발급에 필요한 code를 받는 요청을 하게 됩니다.
인증에 성공하여 code를 발급받게 되면, 해당 코드로 다시 OAuth 서버에 POST 요청을 보내서 사용자의 정보를 얻어올 수 있습니다.

Spring Security를 이용하면 OAuth 2.0 인증을 진행하는 필터에서 OAuth 서버에서 받아온 code로 Post 요청을 보내고 Post 요청으로 받아온 회원의 인증 정보들을 내부적으로 인증 객체에 매핑시켜주게 됩니다.

따라서 사용자의 입장에서는 소셜 로그인 버튼을 눌러서 로그인하면 바로 로그인이 되는 것 같이 보이기때문에 사용자 경험이 매우 증가한다고 할 수 있겠습니다.

🤦 아직 시작밖에 하지 않았다..!

이번 게시글에서는 OAuth 2.0 이라는 라이브러리를 사용하는 이유에 대해서 말씀 드렸습니다.
앞으로 후속 게시글에서는 아래와 같은 내용을 학습하고 개발하며 회원 기능을 완성해보겠습니다.

  • OAuth 2.0 로그인을 위한 Security 설정
  • Redis를 이용한 RefreshToken 관리와 AccessToken 재발급
  • JWTFilter 구현을 통한 JWT 토큰 유효성 검사
  • OAuth 2.0 인증 후 넘어온 사용자의 정보로 회원가입 여부 식별
  • 자체 회원가입을 위한 기타 처리 로직들

읽어주셔서 감사합니다.

다음 시리즈 게시물로 이동
OAuth 2.0 + JWT + Spring Security로 회원 기능 개발하기 - JWT 개념과 Security 기본 설정
게시글로 이동 ->

🙇

참고한 레퍼런스

https://yonghyunlee.gitlab.io/temp_post/oauth-authorization-code/

https://charming-kyu.tistory.com/36

https://hudi.blog/oauth-2.0/

2개의 댓글

comment-user-thumbnail
2023년 5월 20일

정성이 보이는 글이네요 많이 배우고갑니다 감사합니다~

1개의 답글