진행하던 토이 프로젝트에 Spring Security + JWT를 이용해서 로그인을 구현했었는데
이번에는 단순 구현뿐 아니라 JWT에 대하여 좀더 공부해보고 하는 생각으로 글을 씁니다.
먼저 가장 중요한 JWT의 정의에 대하여 알아보아야 겠죠?
JWT란
JWT(Json Web Token)의 약자로 Json 기반의 Web Token입니다.
발급된 토큰값을 Json 객체로 변환 그 후 Clien에게 전송해주는 것을 말하는데요
음 그런데 Jwt가 무엇인지는 대충 알겠는데 왜 JWT를 쓰는 걸까요? 그 전에 Token을 발급해주는 이유는 무엇일까요?
그냥 DB에 ID/PW만 저장하고 Login할 때마다 확인해주면 안될까? 그러면 DB가 해킹당하면.. 큰 문제가 발생하고
또 로그인을 유지하려면 사용자가 API를 불러올 때 마다 DB에 그 사용자가 있는지 확인해줘야 하구요
시간과 비용이 정말 많이 들겠죠
그렇다면 또 DB에 ID/PW만 저장하고 계속 찾는 방법은 좋지 않은 방법이란 걸 알았습니다.
자 그렇다면 로그인 유지를 할 수 있고 안전하고 빠른! 그런한 것이 없을까?
그런 방법을 생각하려면 먼저 인증과 인과에 대하여 먼저 알아보아야 합니다
그런데 인증과 인과 생소한 단아업니다.. 바로 정의부터 볼까요?
인증 (Authentication) -> 로그인 사이트에 회원 권한이 있는 사용자가 ID/Pw를 입력하여 인증을 받는다
그 뒤 서버에게 인증을 받은 뒤 로그인을 시켜주는 것 입니다 사용자의 신원 확인이라고 말할 수도 있겠죠
인가 (Authorization) -> 만약 로그인한 사용자가 티스토리를 하고 있습니다 그런데 글쓰기에서 글을 쓸 때 마다 로그아웃이 됩니다 그러면 안되겠죠?
이렇게 사용자가 어떠한 자원에 접근할 수 있는지를 확인하는 절차가 바로 인가입니다.
자 이제 인증과 인과를 알았으니 돌아와서 인증/인과 방식중 어떠한 것이있고 무엇이 좋을까를 알아봅시다
1. 기존 전통 방식 세션
세션(Session)
일정 시간동안 같은 사용자(브라우저)로부터 들어오는 일련의 요구를 하나의 상태로 보고, 그 상태를 일정하게 유지시키는 기술이다
음 이해하기 조금 어렵죠?
세션의 원리를 한 번 보면
개개인의 사용자에게 고유ID를 부여합니다
그리그 그 ID를 구분해서 사용자 ID에 맞는 서비스를 제공하죠
쉽게 풀어서 얘기하면 어느 놀이공원에 일을 잘하는 알바생이 있습니다.
알바생은 어떤 티켓이 유효한 티켓인지 알고 있습니다.
그렇다면 입구에서 티켓을 검사해 입장가능 한지 판단하여 입장을하게 해주죠
여기서 티켓은->고유ID가 되며 검사하는 알바생은 컴퓨터에서 저장공간이라고 할 수 있죠 일을 잘하니까->메모리라고 생각해줍시다.
그런데 만약 사람들이 너무 몰려와서 줄이 길어지게 되죠 그래서 일을 잘 못하는 알바생을 불러와서 같이 검사를 시킵니다
이처럼 컴퓨터로 바꿔 설명하면 일을 잘 하는 알바생은 여기서 (메모리->속도빠름), 일을 잘 못하는 알바생은 HDD->(속도느림)등이 되겠죠
그리고 여기서 메모리는 휘발성이라 만약 잘하는 알바생이 잠시 일을 쉬었다가 온다면(컴퓨터의 재부팅) 또는 티켓에 유효기간이 지나도 티켓은 유효하지 않게됩니다
결론적으로 이렇게 놀이공원에 들어와있는 상태<->로그인, 검사하는 티켓<->고유ID라고 생각하시면 되겠습니다.
그리고 생각해볼 수 있듯이 문제점으로는 세션은 자원을 사용함으로 많은 요청이 발생할고 많은 자원과 많은 비용이 발생합니다 -> 느리죠!
또한 서버가 여러대이면 한 서버에만 세선이 존재해 세선유지가 안됩니다
자 이제 세션에 대해 조금은 알게 되었습니다
그럼 다음으로는
Cookie란 무엇일까요?
쿠키는 크롬이나 사파리 같은 브라우저에 저장되는 작은 텍스트 조각입니다. 브라우저는 사용자의 컴퓨터에 설치된 소프트웨어이므로 쿠키는 사용자가 갖고 있는 정보라고 할 수 있죠.
예를들어 어떠한 사이트 장바구니에 뭘 담아두어도 몇 분 뒤에 들어가면 상품이 아직 장바구니에 남아있는 것!
그런데 이러한 정보들은 서버에 저장되지 않습니다 사용자가 가지고 있는 데이터이죠 그래서 서버에 큰 부하가 발생하지 않죠 하지만.. 보안에 취약합니다 공격에 노출될 가능성이 커 보통 민감한 정보를 담지는 않습니다
이제 돌고 돌아 처음 얘기했던 JWT로 돌아왔습니다
JWT는 Json으로 토큰을 발급해줍니다!
Token에는 암호화된 정보들이 들어있고 그 정보들을 기반으로 서버는 인가를 해줍니다.
Cookie랑 구조는 그렇게 다르지 않죠
하지만 여기서 중요한 점은 JWT는 서명된 토큰이라는 점입니다.
여기서 서명은 서명 할 때 사용한 키를 사용하여 JSON이 손상되지 않았는지 확인 할 수 있도록 하는 것입니다
JWT의 구성요소로를 크게 3가지가 있습니다 바로 Header, Payload, Signature이죠
1. Header
header에는 보통 토큰의 타입, 서명 생성에 어떤 학교리즘이 사용되었는지 저장합니다.
{
"typ": "JWT",
"alg": "HS256"
}
코드를 보면 토큰 타입은 JWT이고 개인키로 HS256 해싱 알고리즘을 사용합니다
2. Payload
인코딩 돼 있는 Payload는 JSON형식응로 여러 정보들이 들어있고 그 안에는 유효기간, 누구에게 발급했는지, 서버가 사용자에게 어떤 정보를 줄지를 담고있습니다 이정보들을 우리는 Claim이라고 부릅니다
이렇게 Claim이 들어있습니다 간단히 각 키워드를 정의하자면
iss (Issur) : 토큰의 발급자
exp (Expriation Time) : 토큰 만료 시간 등이 있습니다 더 많은 키워드가 있지만 글에서는 여기까지만 다루겠습니다.
아 물론 꼭 위에서처럼 발급할 필요도 없고 더 많은 키워드를 이용해도 됩니다!
그리고 여기서 중요한 점은 Payload에 민감한 정보를 담지 않을 것입니다.
Payload는 그저 인코딩이 돼어있을 뿐이라서 누구나 디코딩을 한다면 안에 값을 알 수 있기 때문입니다
3. Signature
가장 중요한 서명입니다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
1번 헤더의 인코딩 값 2번 페이로드의 인코딩 값 그리고 "시크릿값" 이 셋을 3번 alg 서명 값을 만드는데 알고리즘으로 돌리면 3번 서명값이 나옵니다
페이로드의 정보를 알아도 시크릿값을 모르면 알 수가 없습니다!
만약 Payload의 담긴 정보를 변조해서 JWT로 요청해도 서버가 애초에 발급했던 Signature 안의 Payload와 다르기 때문에 인증이 불가합니다.
이처럼 시간에 따라 바뀌는 어떤 상태값을 안 갖는 걸 stateless하다고 하며 <-> 반대인 상태를 stateful
그렇다면 JWT가 최고냐?
아닙니다 결점이있죠 JWT는 stateless해서 모든 사용자의 상태를 기억하고 가지지 않습니다 만약 이게 되기만 하면 모든 사용자에 제어가 가능하다 하지만 그러면 서버에 저장하고 추적해야 되기 때문에 Session이랑 다른 게 없겠죠?
그런데 여기 JWT에도 문제가 있습니다 토큰이 탈취당해도 무효화 방법이 없다는 점이죠 그래서 실 서비스에서 JWT로만 구현하지 않는다고 합니다.
JWT의 토큰 탈취에는 많은 방법이 있는데 예를들어 Refresh token & Access token을 발급해주는 방식 등..
지금은 글이 너무 길어져서 다음 기회에 다뤄보도록 하겠습니다!
혹시나 궁금한 점 & 제가 틀린 점이 있다면 댓글 꼭 부탁드립니다!!
질문은 환영입니다!
'CS > 네트워크' 카테고리의 다른 글
분산시스템속 브로드캐스트 (0) | 2024.08.06 |
---|---|
[네트워크] ARP 프로토콜 (0) | 2024.04.20 |
[네트워크] 로그란 무엇인가 (0) | 2023.03.05 |
[네트워크] Restful하게? Rest란 무엇일까? (0) | 2023.02.23 |
[네트워크] Protobuf란 무엇인가? (0) | 2023.02.21 |