[고민 & 선택] 왜 OAuth + JWT일까?

윤진원·2023년 7월 6일
19

고민 & 선택

목록 보기
1/1
post-thumbnail

졸업 프로젝트 백엔드 서버 구축이 마무리 단계에 이르렀다.
현재 프로젝트는 OAuth 2.0을 사용한 소셜 로그인 + JWT를 사용하여 권한부여를 하고 있다.

회원가입 & 로그인 인증 방식을 정할 때 고려하고, 고민했던 점들을 기록으로 남기려 한다.


고민 상황 🤔

우선, 왜 일반적인 아이디, 패스워드 방식이 아닌 OAuth 2.0을 사용한 소셜 로그인일까?

OAuth 2.0을 이용한 소셜 로그인을 택한 이유는 여러가지가 있었다.

  1. 사용자 관점에서 봤을 때, 일반적인 로그인 방식보다는 소셜 로그인이 편하지 않을까?
  • 주변 지인들, 그리고 나조차도 일반적으로 웹사이트를 이용할 때 여러 정보를 넣어서 회원가입을 하고.. 로그인 하고.. 이러한 과정들이 귀찮기도 하고 불편했다.

  1. OAuth를 사용하면 인증 과정을 제3자(카카오, 구글..)등에 위임할 수 있다.
  • 웹 서비스를 개발할 때 중요한 부분중 하나가 사용자 인증 과정이라고 생각하는데, 그 부분을 플랫폼에게 맡길 수 있어 비즈니스 로직 개발에 집중할 수 있을 것 같았다.

따라서, OAuth 2.0을 사용해서 소셜 로그인을 할 건데, 그게 다인가?

아니다.
OAuth 2.0을 사용해서 인증 처리를 하면 플랫폼에서 인가 코드가 내려오고, 주어진 인가 코드를 통해서 토큰 발급을 요청할 수 있다.


그럼 그냥 그 토큰을 사용해서 추가적인 인증 처리를 하면 될려나?

아니다!

이 생각은 정말 짧은 생각이였다.

보통 플랫폼에서 내려주는 Access Token들은 짧은 유효 기간을 가지며, 별도의 서명이나 암호화 과정이 수행되지 않은 경우도 많다.
따라서, Access Token에 담긴 사용자 식별 정보, 개인 정보들이 중간에 탈취될 수도 있다.


그럼 뭘 사용해야 하지?

보통 인증 처리를 위해 세 가지 방법을 주로 사용한다.

  • 세션
  • 쿠키
  • JWT

세션, 쿠키, JWT가 무엇인지는 이미 너무 많은 블로그에 나와있으니 생략하고, 장단점과 왜 내가 JWT를 택했는지를 알아보자!


우선, 우리가 사용하는 HTTP 프로토콜은 Stateless 하다!

  • Stateless 하다는 특징 때문에, 클라이언트와 서버는 서로의 이전 상태를 기억하거나, 유지하지 않는다.
  • 서버측에서 상태를 계속 유지해야 한다면 서버의 부하도 그에 따라 증가할 것!

그럼 Stateless 하게 개발하면 만약 글을 쓰거나 로그인, 상품을 주문할 때 계속해서 새롭게 인증을 해야하나?

아니다!
그래서 나온 것이 쿠키, 세션, JWT였다.


보통 일반적인 로그인을 구현할 때 세션과 쿠키도 많이 사용한다.
하지만 여러 단점들이 존재!


세션 + 쿠키 방식의 단점 🤢

우선 쿠키를 사용하는 방식은 브라우저에 데이터를 저장하여 서버에 요청시, 헤더에 쿠키를 동봉하여 보낸다.

Headers = [Set-Cookie:"userName=jinwon", "password=1234"]
  • 클라이언트의 브라우저에는 작은 기록 정보 파일이 남겨진다.
  • 서버는 쿠키에 담긴 정보를 바탕으로, 해당 요청의 클라이언트를 식별할 수 있다!

쿠키의 단점 🤢

  1. 보안에 취약하다.
  • 요청시, 쿠키의 값을 그대로 내보낸다.
  • 유출될 수 있고, 악의적인 목적에 따라 조작 당할 수 있다.
  1. 용량 제한이 있어 많은 정보를 담을 수 없다.
  2. 브라우저간 공유가 불가능하다.

그렇다면, 세션 + 쿠키 방식은 괜찮을까?

그래서 함께 사용할 수 있는 방식이 세션 + 쿠키이다.
세션은 클라이언트의 인증 정보를 쿠키가 아닌, 서버 측에 저장하고 관리한다.


Set-Cookie: SESSIONID=FD97JKHSD22KJ12NH412H51JHK2141J;
  • 서버는 인증 정보는 서버에 저장하고, 클라이언트 식별자로 세션 ID를 발급받아 쿠키에 담는다.
  • 이후, 클라이언트는 요청을 보낼 때 마다 세션 ID가 담긴 쿠키를 보내서 인증한다.

세션 + 쿠키 방식 또한 단점이 존재한다!

  1. 세션 ID 자체는 개인 정보를 담고 있지 않지만, 해커가 탈취하면 클라이언트인척 위장할 수 있다.
  2. 서버에서 세션 저장소를 사용하므로, 요청이 많아지면 서버에 부하가 심해진다.

왜 JWT를 사용했을까? 😌

그에 따라 생각한 방식은 JWT!

우선, OAuth 2.0을 사용하여 소셜 로그인을 진행하면 플랫폼에서 토큰을 내려준다.

따라서 JWT로 토큰을 추가적으로 가공하여 사용하면 괜찮지 않을까?


물론, JWT를 사용하는 방식도 단점은 존재한다.

JWT 방식의 단점 🤢

  1. 토큰의 길이가 길어, 인증 요청이 많아질수록 네트워크 부하가 심해진다.
  2. Payload 자체는 암호화되지 않기 때문에, 사용자의 중요한 정보는 담을 수 없다.
  3. 토큰은 한 번 발급되면 유효기간이 만료되기 전까지 계속 사용 가능하기 때문에, 탈취당하면 대처하기 어렵다.

그럼에도 불구하고, 왜 JWT를 택했을까?

  1. Header와 Payload를 가지고 Signature를 생성하므로, 데이터 위변조를 어느정도 막을 수 있다!
  2. 인증 정보를 저장하기 않기 때문에, 서버는 Stateless 가 된다.
  3. 토큰 탈취 방지를 위해 여러 전략을 사용 가능하다.

토큰 탈취 방지를 위해 어떤 전략을 사용하지?

필자의 경우, Access Token은 1시간, Refresh Token은 일주일로 현재 설정을 해놓았다.

Refresh Token을 사용함으로써, Access Token을 탈취당하더라도 짧은 토큰 유효 시간을 두어 손실을 최소화 시켰다.

또한, Refresh Token의 유효기간이 아직 만료되지 않았다면, Access Token이 만료되더라도 사용자가 요청을 보내면 재발급 가능하게 하여 사용자의 잦은 로그인을 막았다.


하지만, 항상 Trade-Off 는 존재한다!

이렇게 되면 서버는 Refresh Token을 별도의 저장소에 저장해야 한다.

나는 현재 데이터베이스가 아닌, Redis에 저장을 해두었다.

별도의 저장소가 필요없다는 JWT의 장점이 없어지지만, 그래도 OAuth 플랫폼에서 내려주는 토큰을 가공시켜 사용할 수 있다는 점, 그리고 보안을 위해 어쩔 수 없다는 점을 염두에 두어야 한다.


서비스가 결제와 같은 민감한 컨텐츠라면, 비밀번호를 한 번 더 입력하는 것이 크게 문제가 되지 않는다.

반면, 게시글에 글을 작성할 때마다 로그인을 다시 해야 한다면 사용자들은 매우 귀찮아진다.

결국 완벽한 장점만을 누릴 수는 없는 것 같다!


참고

profile
기억보단 기록을

0개의 댓글