본문 바로가기
서버 & 네트워크

인증과 인가(쿠키, 세션, JWT)

by 자바지기 2021. 10. 10.

인증 : authentication

특정 서비스에 일정 권한이 주어진 사용자임을 인증 받는 것

 

인가 : authorization 

한 번 인증을 받은 사용자가 이후 서비스의 여러 기능들을 사용할 때 서버에서 사용자가 로그인 되어있음을 알아보고 허가 해주는 것

 

 

 

쿠키와 세션

HTTP 프로토콜은 서버-클라이언트 통신 시 stateless 방식으로 통신을 한다. stateless 방식을 쉽게 말하면 브라우저에서 통신이 끝나면 상태를 유지하지 않으므로 새 웹 페이지를 열 때 기존 웹페이지

park-algorithm.tistory.com

앞서 쿠키와 세션에 관해 살펴보았다. 

 

쿠키와 세션을 이용하여 인가를 구현 하면 다음과 같은 문제가 발생한다.

 

1. 세션은 stateful이다.

세션의 문제점은 REST의 제약 조건을 지키지 못한다. 앞선 REST API 게시글에서 REST의 제약 조건을 알아보았다. 세션은 HTTP의 Stateless를 지키지 못한다.

(Stateless(무상태) : 각 요청 간 클라이언트의 콘텍스트가 서버에 저장되어서는 안 된다. 즉 서버는 작업을 위한 클라이언트의 상태 정보를 따로 저장하고 관리하지 않는다. 따라서 서버는 들어오는 요청만을 단순히 처리하면 된다)

 

2. 세션을 이용한 인가 방식은 서버의 메모리에 부담을 준다.

사용자가 로그인을 하면 서버는 사용자에게 세션 id를 주고 서버의 메모리에 세션 id를 저장한다.

브라우저는 쿠키에 세션 id를 저장한다. 사용자가 브라우저를 통해 요청을 하면 서버는 브라우저에서 보낸 쿠키의 세션 id를 메모리에서 조회하는 방식이다. 이를 통해 로그인 유무를 알 수 있다.

이 방식은 서버의 메모리에 부담을 준다. 동시에 접속한 사용자가 많을 경우 서버의 메모리가 부족해진다. 또한 서버가 재부팅 해야하는 상황이 오면 메모리에 저장되어있던 세션 id가 모두 사라지게 된다.  

 

3. 쿠키와 세션의 정보가 유출되면 보안의 위험이 있다.

 

4. 쿠키는 클라이언트 내에 존재하므로 변조, 위조가 될 수 있다.

 

따라서 쿠키와 세션을 통한 로그인 인가 방식은 바람직하지 않다.

 

이런 이유로 부담 없이 인가를 구현하기 위해 고안된 것이 JWT 이다.


JWT

JSON Web Token의 약자이다.

사용자가 로그인을 하면 서버에서 Token을 건내준다. 

이 token은 암호화된 3가지 데이터를 이어붙인 것이다.

 

1. Header

header를 디코딩하면 두 가지 정보가 있다.

  • type: 항상 jwt가 들어간다.(고정값)
  • alg : 알고리즘의 약자, Verify signature를 만드는데 사용될 알고리즘이 지정된다.

2. Payload

payload를 base64로 디코딩 해보면 JSON형식으로 여러 정보들이 들어있다.

  • iss:  토큰 발급자
  • sub: 토큰 제목
  • aud : 토큰 대상자
  • exp : 토큰의 만료시간 
  • 그 외에 서비스가 사용자에게 이 토큰을 통해 공개하기 원하는 내용(ex : 사용자의 닉네임, 서비스상의 레벨, 관리자 여부 등)을 서비스 측에서 원하는 대로 담을 수 있다.     

이 토큰에 담긴 데이터를 claim이라고 한다.

 

사용자가 서버에게 요청을 하면 서버는 사용자 정보를 알기 위해 사용자에게 토큰을 받아서 claim 데이터를 읽는다. 

이는 서버가 요청마다 일일이 데이터베이스에서 뒤져봐야할 것들이 줄어드는 것이다.


3. Verify signature

(header + payload + 서버에 감춰놓은 비밀 값)을 암호화 알고리즘에 넣으면 Verify signature 값이 된다.

서버는 요청에 토큰이 들어오면 (header + payload + 서버에 감춰놓은 비밀 값)을 알고리즘에 넣은 값과 Verify signature 값이 일치하는 결과가 나오는 지 확인한다. 서버가 아닌 다른 곳에서 claim을 변경하였다면 이 두 값이 일치하지 않을 것이다. 값이 일치하지 않다면 서버에서 요청을 거부하게 된다.

값이 일치하고 유효기간도 지나지 않았다면 사용자는 인가를 받게 된다.

 

이 JWT는 세션과 다르게 stateless이다.

 

JWT의 단점

JWT방식에서 토큰은 서버가 아닌 클라이언트에 존재하므로 서버에서 통제할 수 없다.

예를 들어 세션을 이용한 인가 방식에서는 서버의 메모리에서 세션 id를 지워버리면 사용자를 강제로 로그아웃 시킬 수 있다. 그러나 JWT 방식으로는 서버에서 관리할 수 없기 때문에 이러한 기능을 구현하지 못한다. 또한 이 토큰이 외부로 유출되었을 때 서버에서 이 토큰을 무효화할 방법도 없다. 

 

이를 해결하기 위한 방법 :

사용자가 로그인을 하면 서버에서 두 개의 토큰을 발급한다.

서버는 클라이언트에게 수명이 짧은 access 토큰과 수명이 긴 refresh 토큰을 발급하고 refresh 토큰의 상응값을 데이터베이스에 저장한다. 사용자는 access 토큰의 수명이 다하면 refresh 토큰을 서버에게 보낸다. 서버는 refresh 토큰을 데이터베이스에서 조회해보고 맞다면 새 access 토큰을 사용자에게 보낸다. 이 refresh 토큰이 안전하게 관리된다면 refresh 토큰이 유효할 동안에는 access 토큰이 만료될 때마다 다시 로그인할 필요없게 된다.

서버에서 사용자를 강제 로그아웃 시키려면 데이터베이스의 refresh 토큰을 삭제하면 된다. 그렇게 하면 사용자가 refresh 토큰을 보내도 서버에서 새로운 access 토큰을 보내지 않을 것이기 때문이다. 그렇지만 access 토큰이 유효한 동안에는 이를 바로 차단할 방법은 없다.. 이것이 JWT의 한계이다.

 

댓글