개발공부/spring boot

JWT_인증/인가

기억지기 개발자 2023. 6. 5. 17:43

❤️인증(Authentication)

로그인. 내가 이 사이트에 가입된 회원임을, 즉 특정 서비스에 일정 권한이 주어진 사용자임을 아이디와 패스워드 등을 통해서 말 그대로 인증 받는 것이다.

❤️인가(Authorization)

이렇게 한 번 인증받은 사용자가 후에 사이트의 여러 기능들을 사용할 때 사용하는 방법으로, 즉 이를테면 내가 페북에 로그인으로 인증을 하고 '나서' 내 친구들의 목록을 보거나 내 페이지에 글을 작성하거나 내 계정으로'만' 할 수 있는 활동들을 하고자 할 때. 페이스북이 내가 로그인 되어 있음을 알아보고 허가를 해주는 것이다.
로그인이 유지되는 상태에서 일어나는 일이라고 이야기할 수 있다.


❤️JWT

  • JWT를 사용하는 서비스에서는 사용자가 로그인하면 토큰이라는 표를 출력해서 건네준다. 토큰만 줘버리고 서버는 그냥 잊어버린다. (기억하지 않는다.) 
  • JWT의 생김새는 XXXXXXXX.YYYYYYYYY.ZZZZZZZZZZZ 이렇게 생겼는데 이 마침표를 기준으로 세 부분으로 나뉘는 것이다. 각각 header, payload,verify signature로 구분된다. 

payload

payload에 있는 곳을 Base64로 디코딩해보면 JSON형식으로 여러 정보들이 들어있다. 이 토큰을 누가 누구에게 발급했는지, 이 토큰이 언제까지 유효한지, 서비스가 사용자에게 이 토큰을 통해 공개하기 원하는 내용(예) 등급별 서비스)등이 있다. 이렇게 토큰에 담긴 사용자 정보 등의 데이터를 Claim이라고 한다.

그런데 이 정보들이 특별히 암호화되어 있는 것도 아니고 다시 디코딩만 하면 사용자가 이것을 조작해서 악용할 수도 있다는 말이 될 수도 있기 때문에 header와 서명이 있는 것이다. 

header

두 가지 정보가 담겨있는데, 

  1. type이라는 것은 토큰의 타입인데 여기에는 언제나 JWT가 들어간다. 타입이 JWT어야 JWt인것이다. 고정값이다.
  2. alg이다. 이것이 중요하다. 알고리즘의 약자인데 여기에는 서명 값(verify signature)을 만드는데 사용된 알고리즘이 지정된다. 여러 암호화 방식 중에 하나를 지정할 수 있다. 헤더와 페이로드 그리고 '서버에 감춰놓은 비밀 값' 이 셋을 이 암호화 알고림즘에 넣고 돌리면 서명 값이 나오는 것이다. 
  • 암호화 알고리즘이라는 것이 한쪽 방향으로는 계산이 돼도 반대쪽으로는 안 되는 거라, 서버만 알고 있는 그 비밀 값울 찾아낼 방법이 없는것이다. 
    글자 하나만 바뀌어도 알고리즘에 의해서 서명의 값이 완전히 달라지는 것이기 때문에 페이로드를 수정해서 유효한 3번 값이 나오려면 반드시 서버에 숨긴 비밀키를 알고 있어야하기 때문에 조작이 불가능해 지는 것이다.
  • 서버는 요청에 토큰 값이 실려들어오면 헤더와 페이로드의 값을 '서버의 비밀 키'와 함께 돌려봐서 계산된 결과값이 서명 값과 일치하는 결과가 나오는지 확인한다. 

JWT의 단점

세션처럼 stateful해서 모든 사용자들의 상태를 기억하고 있다는 건 구현하기 부담되고 고려사항도 많지만, 이게 되기만 한다면 기억하는 대상의 상태들을 언제든 제어할 수 있다는 의미이다. 예를들어 한 기기에서만 로그인 가능한 서비스를 만들려는 경우에 PC에서 로그인한 상태의 어떤 사용자가 핸드폰에서 또 로그인하면 PC에서는 로그아웃되도록 기존 세션을 종료할 수 있다는 것이다. jwt는 서버가 정보를 기억하고 있을 필요가 없어서 편하기는 한데 그래서 통제를 못한다는 점과 나쁜 사람이 토큰을 중간에 가로챈다면 그것을 무효화 할 수 있는 방법이 없다는 단점이 있다.  

단점의 극복

단점을 조금 더 무효화 하고자 있는 방법이 만료시간을 가깝게 잡아서 토큰의 수명을 아주 짧게 주는 것이다.
그러면 몇 분뒤에 또 로그인을 해야하는 상황이 발생하기 때문에 로그인을 하고 나면 토큰을 두 개를 준다. 수명이 몇 시간이나 몇 분이하로 짧은 access 토큰이랑 꽤 길게, 보통 2주 정도로 잡혀있는 refresh 토큰을 준다.

그 중에 가장 대표적인 방법이 

  1. access 토큰과 refresh 토큰을 발급하고 이 2가지를 클라이언트에게 보냄.
  2. refresh 토큰은, 상응값을 DB에도 저장한다. 
  3. 클라이언트는 access토큰의 수명이 다하면 refresh 토큰을 서버로 보낸다.
  4. 서버는 그것을 DB에 저장된 값과 비교해보고 맞다면 새로운 access 토큰을 발급해준다. 
  5. 이 refresh 토큰만 안전하게 관리된다면 이게 유효할 동안은 access 토큰이 만료될 때마다 다시 로그인을 할 필요가 없이  새로 발급을 받을 수 있는 것이다.
    ➡️매번 인가를 받을 때 쓰는 수명 짧은 토큰이 access 토큰이고 엑세스 토큰을 재발급 받을 때 사용하는 것이 refresh 토큰이다.