1일 1개념정리 24.08.09.금 ~
큰 결정에 큰 동기가 따르지 않을 때도 있다. 하지만 큰 결심이 따라야 이뤄낼 수 있다.
무조건 무조건 1일 1개의 개념 정리하기 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#51. JWT
어제는 OAuth에 대해서 알아보았다. 이때 같이 언급되는 것이 있는데 바로 JWT이다. json web token(java web token인줄 알았다 .....)이라고 불리는 JWT는 보통 스프링 프로젝트를 하다보면 로그인에서 애용되는 방식이다. 오늘은 JWT에 대해서 알아보자.
생활코딩 유튜브를 보고 정리하였습니다.
https://www.youtube.com/watch?v=36lpDzQzVXs
JWT = 편지 보내기
일단 약간 보안의 내용을 곁들인 JWT를 이야기해보자. JWT를 하나의 편지라고 생각해보자. 편지를 보낼 때 누가 보냈는지 검증해야한다. 일단 편지는 3가지 요소가 있다.
- 편지 봉투 (헤더)
- 편지지 (페이로드 = 내용)
- 누가 썼는지 알려주는 이름 (시그니처 = 서명)
JWT에서 내용을 "payload"라고 하고, 페이로드의 각 부분들을 "클레임"이라고 한다. 클레임은 주장이다. 그니까 내가 이런 내용을 썼고, 난 누구다 이런 것을 주장할뿐, 그걸 보장해주진 않는다. 이걸 보장해주는 것이 바로 시그니처 즉 서명이다.
이때, 서명 방법이 여러가지가 있다. 보통 HS256 방법으로 서명한다. 그리고 이런 방식으로 서명했다~ 라는 내용을 헤더에서 알려준다. 이런식으로 서명까지 완료되면 그대로 보내면 되느냐 ? 아니다. 그냥 보내지 않고, base64 방법으로 인코딩한다.
여기까지 끝나면 헤더, 페이로드, 시그니처가 인코딩된 상태이다. 그리고 이것을 이어준 것이 JWT이다.
header.payload.signature 처럼 이어준다. 그럼 이런식으로 나온다. 랜덤하게 뽑아낸 jwt 토큰이다. (base64로 인코딩된 모습)
이렇게 나뉜 3개의 구간이 각각 헤더, 페이로드, 시그니처이다.
시그니처 (서명)
서명이라는 게 어떻게 이뤄지는지 간단하게만 알아보자. 누군가 디지털상에서 "나 민수예요 오늘 300만원 보내주기론 한거 잊지 않았죠 ? 여기 계좌번호 1234..... 보내주세요" 이러면 내가 민수인지 어떻게 알까 ?? 이때 민수는 300만원을 달라는 내용을 헤더, 서명과 함께 보내준다. 그럼 일단 사기꾼인지 의심이 든다. 그니까 서명을 대조해봐야한다. 민수가 보낸 헤더를 보니 HS256 알고리즘으로 서명을 했다고 하는군. 그럼 내용을 HS256 알고리즘에 넣는데, 이때 내가 민수임을 확인하는 비밀 키를 함께 넣어준다. 그럼 서명이 톡 나온다. 이 서명을 민수가 보낸 서명과 비교하는 것이다. 그럼 아 민수 맞구나 하고 인증이 되는 원리이다.
쿠키 기반 인증 (Session id)
JWT를 알아보기 전, 쿠키 기반 인증에 대해 알아보자. 내가 브라우저에서 로그인을 하면, DB에 가서 유효한 사용자인지 확인해야 한다. 만약 존재하는 회원이라면 ?? 세션 테이블에 세션 id와 유저id를 기록해놓고, 서버로 이 세션 id를 반환한다. 그럼 바로 이 세션 id가 브라우저 쿠키로 저장되고, 서비스에 들락날락 거릴 때 이것을 가지고 출입한다. 근데 만약 내 이름이 필요한 상황이라면 ??? 세션 테이블에선 아까 세션 id와 유저 id만 기록해놨기 때문에, 이 유저 id를 가지고 다시 회원을 조회해서 이름을 가져와야한다. 번거롭다 .... 그래서 다음과 같은 단점이 있다.
- 사용자 정보가 필요할 때 사용자를 다시 조회해야한다.
- 사용자가 서비스에 접속할 때마다 세션 테이블에 가서 session_id를 매번 확인해야한다.
- 그리고 만약 다른 브라우저에서 접속한다면 ?? session_id를 다시 발급해줘야한다. → 세션 테이블이 엄청나게 커짐
토큰 기반 인증 (JWT)
앞서 쿠키 기반 인증에선 세션 관리를 서버에서 처리하므로 서버 부하가 커진다는 것과, 사용자 정보 조회 시 추가적인 DB요청이 필요하는 등의 단점이 있었다. JWT는 이런 단점들을 해결할 수 있을까 ??
JWT는 서버가 발행하는 토큰이다. 로그인을 시도하면 유효한 사용자인지 DB에 가서 확인하고, 유효하면 토큰을 발급한다. 토큰은 앞서 말했듯이 payload와 비밀키를 가지고 서명을 만들어내고 헤더, 페이로드, 서명을 온점으로 이어서 토큰이 만들어진다.
→ 그럼 이 토큰을 브라우저에게 전달한다. 아니 그럼 토큰을 base64로 디코딩하면 서명 털리는 거 아닌가 ??? 물론 디코딩했을 때 헤더와 페이로드의 정보는 알 수 있다. 근데 서명은 애당초 비밀키를 가지고 한번 더 암호화를 거친 값이고, 비밀키는 서버쪽에만 있기 때문에 신뢰할 수 있다.
이때 장점이 나오는데, jwt의 payload 부분에 이름, 이메일 등 자주 쓰이는 것은 담을 수 있다. 앞서 세션테이블에서 사용자 정보가 못담기는 이유가 세션테이블이 너무 커질 수 있다는 점이었는데 JWT는 페이로드에 정보를 더 담을 수 있어 유용하다.
그럼 현재 흐름을 보면 브라우저에게 JWT을 보냈다. 이걸 가지고 어떻게 인증할까 ? 다른 서비스에 접속할 때, 토큰을 서버로 넘겨준다. JWT에는 헤더, 페이로드, 시그니처가 있고,,, 서버측에서 JWT의 페이로드와 비밀키를 가지고 서명을 만들었을 때 이 두개가 서로 일치한다면 사용자임이 인정되는 것이다. 왜냐면 애당초 비밀키는 서버쪽에만 있기 때문이다.
→ 그래서 JWT토큰이 일단 한번 발급만 되면, 사용자 인증은 이런 시그니처를 만드는 과정으로 대체한다. 그래서 DB에 접근할 필요가 없어진다. 그래서 DB접근이 없어 서버 부담을 줄일 수 있다. (세션 테이블 필요 없음)
Q. 그럼 서버의 비밀키가 탈취당하면 시그니처를 누구나 만들어내서 서버를 속일 수 있나요 ??
A. YES. 왜냐하면 비밀키를 알고 있는 사람이라면 누구나 유효한 서명을 생성할 수 있기 때문에, 악의적인 공격자가 임의의 토큰을 발급하고 서버를 속일 수 있다. 따라서 비밀키는 반드시 안전하게 관리되어야 한다.
여기에 가면 JWT 토큰을 만들고, 헤더 페이로드 시그니처가 어떻게 생겼는지 체험해볼 수 있다.
'1일 1개념정리 (24년 8월~) > Spring' 카테고리의 다른 글
1일1개 (67) - DB에서 삭제한줄 알았지? (0) | 2024.10.22 |
---|---|
1일1개 (59) - 영속성 (0) | 2024.10.13 |
1일1개 (50) - OAuth 2.0 (0) | 2024.10.04 |
1일1개 (31) - mappedBy (다시 수정하기) (0) | 2024.09.10 |
1일1개 (15) - 콩 너는 죽었다 (0) | 2024.08.24 |