세션,토큰,JWT 를 공부하기전에 알아두어야할 것이 있습니다.
바로 인증,인가 이 두가지 입니다.
이제 기본 용어는 공부했으니 본론으로 들어가보겠습니다.
세션 표딱지
라는 것을 출력합니다.(영화관 티켓을 생각합니다.)JWT
입니다.표
를 출력해서 건네줍니다..
이 두군데에 들어가있습니다.Header
,Payload
,Verify Signature
(헤더,페이로드,서명)으로 나뉩니다.Claim
이라고 합니다.하지만 여기서 생각한것이 이렇게 중요한 것을 특별한 암호화도 아니고 인코딩 되어있는 것이라면, 사용자가 프로그래밍 언어를 이용하여 다시 디코딩하여 볼수도 있으며, 조작이 가능하지 않을까? 라는 생각이 들었습니다. 마음만 먹는다면 악용도 가능할 수도 있습니다. 예를들어 유효기간을 늘린다던가, 관리자 여부를 TRUE로 설정하여 관리자 권한으로 인가를 받을 수 있습니다.
그래서 있는 것이 Header 와 Verify Signature 입니다.
이 것을 디코딩 해보면 아래와 같이 나옵니다.
typ(type) : 토큰의 타입
alg(Algorithm) : 알고리즘
HS256
등 여러 암호화 방식 중 하나를 지정할 수 있습니다.1번 Header 와 2번 Paylaod , 그리고 "서버에 감춰놓은 비밀값" 이 셋을 이 암호화 알고리즘에 넣고 돌리면 3번 서명값이 나오게 됩니다.
즉, 이 암호화 알고리즘이라는 것이 한쪽 방향으로는 계산이 간으해도 반대로는 불가능하여, 서버만 알고 있는 비밀값을 찾을 방법이 없습니다.
만약 토큰 값을 알고 2번 페이로드를 수정하여 유효한 3번 서버값이 나오려면 서버에 숨긴 "비밀키"를 알고 있어야 하기에 조작이 불가능합니다.
- 서버는 요청에 토큰값이 실려들어오면 1,2번의 값을 "서버의 비밀 키"와 함께 돌려 봐서 계산된 결과 값이 3번 서명값과 일치하는 결과가 나오는지 확인합니다.
3번 서명값과 계산 값이 일치하고, 유효기간도 지나지 않았다면 그 사용자는 로그인 된 회원으로 인가를 받습니다.
그래서 서버는 사용자의 상태를 따로 기억해 둘 필요없이, 비밀값만 가지고 있으면 요청이 들어올 떄마다 토큰을 스캔하여 인가를 판별합니다.
이처럼 시간에 따라 바뀌는 어떤 상태값을 갖지 않는 것을 "stateless하다" 라고 하고, 반대로 "Sessioin은 stateful하다" 라고 합니다.
하지만 여기서 궁금했습니다. 그렇다면 무조건 Session 보다는 JWT을 써야 하지 않을까???
저만 그런게 아닐까 생각합니다.하지만 세션을 대체하기에는 JWT가 큰 결점을 가지고 있습니다.
세션처럼 stateful, 모든 사용자들의 상태를 기억하고 있다는 것은 구현하기 부담되고, 고려사항도 많지만 이게 되기만 한다면 기억하는 대상의 상태들을 언제든지 제어할 수 있다는 의미입니다.
예를들어, 한 기기에서만 로그인 가능한 서비스를 만드는 경우 PC에서 로그인한 상태의 어떤 사용자가 핸드폰에서 또 로그인하면 PC에서는 로그아웃되도록 기존 세션을 종료할 수 있다는 것입니다.
이미 줘버린 토큰을 다시 뻇을 수도 없고, 그 토큰의 발급 내역이나 정보를 서버가 어디 기록해서 추적하고 있는 것도 아니기 때문입니다.그래서 통제가 불가능합니다.
심지어 악성프로그래머가 이 토큰을 가져갔는데, 이 토큰을 무효화할 방법도 없습니다. 때문에 실 서비스중에 JWT만으로 인가를 구현하는 곳은 생각보다 많지는 않습니다.
물론 해결방법으로는 만료시간을 짧게 잛아서 토큰의 수명을 아주 짧게 부여합니다.
물론 또 이렇게 짧게 준다고 하면 일정 시간 뒤에 또 재로그인을 할 상황이 발생하게 되어, 로그인을 하고나면 토큰을 2개를 줍니다.