JWT (JSON Web Token)는 웹 표준으로, 두 당사자 간에 정보를 JSON 객체로 안전하게 전송하기 위해 설계되었다. 주로 인증 및 정보 교환에 사용되며 JWT는 헤더(Header), 페이로드(Payload), 그리고 서명(Signature) 으로 구성된다.
1 URL에 아이디와 비밀번호 포함: 초기 웹 시대에는 사용자 인증을 위해 URL의 쿼리 문자열(query string)에 아이디와 비밀번호를 포함시키는 방식이 사용되었다.
2 헤더를 통한 인증 정보 전송: URL에 정보 노출의 문제를 해결하기 위해, 아이디와 비밀번호를 HTTP 요청의 헤더에 포함시키는 방식으로 변경되었다.
3 API 키 사용: 보안을 더욱 강화하기 위해, 사용자의 아이디와 비밀번호를 직접 전송하는 대신 고유한 API 키를 사용하는 방식이 도입되었습니다. API 키는 사용자를 식별하는 데 사용되며, 매 요청마다 전송된다.
4 JWT: I/O 작업을 줄이고, 보안을 강화하기 위해 JWT (JSON Web Token)가 등장했다. JWT는 사용자 인증 정보를 자체적으로 포함하는 토큰으로, 서버는 이 토큰을 검증하여 사용자를 인증한다. JWT는 상태를 서버에 저장할 필요가 없는(stateless) 방식이기 때문에, 서버의 성능과 확장성을 향상시킬 수 있다.
JWT (JSON Web Token)는 I/O 작업 없이 자체 연산만으로 그 위변조 여부를 파악할 수 있다.
서명 생성: 서명은 토큰의 헤더와 페이로드를 각각 Base64로 인코딩한 후, 서버에 저장된 비밀키(secret key) 또는 공개키/개인키 쌍을 사용하여 해시한다. 이 과정은 서버 내에서 이루어지며 외부 I/O 작업을 필요로 하지 않는다.
서명 검증: JWT를 받는 측(일반적으로 서버)은 토큰의 헤더와 페이로드를 같은 방식으로 인코딩하고, 토큰에 포함된 서명과 비교한다. 이 때 사용되는 비밀키 또는 공개키는 서버 내에 저장되어 있기 때문에, 외부 데이터베이스나 API에 접근할 필요가 없다.
위변조 확인: 서명이 일치하면 토큰이 위변조되지 않았다고 판단한다. 서명이 불일치하면 토큰이 위변조되었거나 잘못된 키로 서명되었다고 간주한다.
이 과정은 모두 서버 내부에서의 연산으로 처리되며, 별도의 외부 데이터베이스 접근이나 네트워크 I/O 작업 없이 진행된다. 이러한 특성 때문에 JWT는 상태를 유지할 필요가 없는 스테이트리스(stateless) 인증 메커니즘으로 널리 사용된다.
Spring Security의 Principal 객체는 전통적인 세션 기반의 상태 유지(Stateful) 방식을 사용하며, 서버 측에서 사용자 인증 정보를 관리한다.
JWT는 상태 비유지(Stateless) 방식을 사용하며, 인증 정보를 클라이언트에 저장하고 서버는 토큰 검증을 통해 사용자를 식별한다.
간단히, 서버측에 저장되느냐 클라이언트측에 저장되느냐의 차이.
상태 관리: 서버 측 저장은 상태 유지 방식이며, 클라이언트 측 저장은 상태 비유지 방식이다.
보안: 서버 측 저장은 클라이언트의 직접적인 접근으로부터 보호되는 반면, 클라이언트 측 저장은 토큰을 안전하게 관리해야 하는 책임이 증가한다.
확장성과 유연성: 클라이언트 측 저장 방식은 확장성이 뛰어나지만, 서버 측 저장 방식은 상태 동기화의 복잡성을 가질 수 있다.
서버 부하: 서버 측 저장 방식은 서버 리소스에 더 큰 부하를 줄 수 있으며, 클라이언트 측 저장은 이러한 부하를 줄일 수 있다.
JWT 토큰을 관리하는 두가지 방법.
블랙리스트 방식은 특정 항목들을 금지하거나 차단하는 방법이다. 이 방식에서는 블랙리스트에 등록된 항목들만이 접근이 제한되거나 차단되며, 블랙리스트에 없는 모든 항목은 기본적으로 허용된다.
화이트리스트 방식은 특정 항목들만을 허용하고, 그 외의 모든 항목을 차단하는 방법이다. 이 방식에서는 화이트리스트에 등록된 항목들만이 접근이 허용되며, 그 외의 모든 것은 기본적으로 차단된다.
장점: 화이트리스트에 없는 모든 새로운 또는 미확인 항목은 자동적으로 차단되므로 보안 위협에 대한 노출이 줄어든다.
단점: 유지 관리가 더 어렵고 유연성이 낮다. 화이트리스트를 정기적으로 업데이트하고 관리해야 하며, 허용된 항목만 사용할 수 있어 사용자 경험이 제한될 수 있다.
JWT 토큰에 사용자 정보를 담아 사용함으로써 I/O 작업의 빈도를 줄여보고자 했는데...
블랙리스트, 화이트리스트 조회한다고 db 를 조회하면 이게 다 무슨소용?
그래서
JWT 토큰을 관리하기 위한 두가지 토큰이 있다.
엑세스 토큰은 사용자가 시스템이나 애플리케이션에 접근할 권한을 가지고 있음을 나타내는 토큰이다.
리프레시 토큰은 사용자가 새로운 엑세스 토큰을 요청할 수 있도록 하는 토큰이다.
엑세스토큰의 유효기간이 짧음으로 야기되는 문제는 유효기간이 끝날때마다 로그인을 해야된다는 점 이를 위해 리프레시 토큰을 사용한다.
HTTP ONLY 쿠키로 두 토큰을 응답해보자.
HTTP ONLY 쿠키이기 때문에 프론트 엔드 개발자가 토큰관리를 안해도 된다.
매 요청마다 수동으로 엑세스 토큰을 추가하는 코드를 작성할 필요가 없다.
매 요청마다 엑세스 토큰의 만료를 걱정할 필요가 없다.