CS
세션 로그인 VS JWT 로그인
사과만쥬
2024. 8. 24. 22:15
최근 스프링 시큐리티를 제대로 알고 구현하고 싶어서 유데미에서 관련한 강의를 듣고 있다.
싸피 프로젝트를 하면서는 막연하게 JWT를 팀원들이 쓰자고 해서 썼기 때문에, 이번 기회를 통해서 왜 JWT를 많이 쓰는지에 대해 알아보고자 한다.
인증&인가 과정에서의 토큰의 역할
토큰의 형태
- UUID(범용 고유 식별자) 형식의 일반 문자열
- JWT(Json Web Token)
- 일반적으로 로그인 중 사용자가 처음 인증할 때 생성됨
- CSRF 토큰
- CSRF 공격으로부터 애플리케이션 보호
- JSESSIONID
- Spring Security에서 기본적으로 생성해주는 토큰으로, 매번 백엔드에 자격 증명을 공유하지 않도록 도와줌.
토큰의 작동 과정
제한된 리소스에 대한 모든 요청에서 클라이언트는 쿼리 문자열 또는 Authorization 헤더에 액세스 토큰을 보냅니다. 그런 다음 서버는 토큰의 유효성을 검사하고, 유효한 경우 보안 리소스를 클라이언트에 반환합니다.
토큰의 장점
- 보안
- 모든 요청에 대해 자격 증명을 공유하지 않도록 도와줌.
- 사용자 자격 증명을 무효화하지 않고도 토큰 무효화 가능
- 짧은 수명으로 생성 가능
- 역할이나 권한과 같은 사용자 관련 정보를 저장하는 데 사용될 수 있음
- 재사용성(Reusability)
- 여러 플랫폼과 도메인에서 실행
- 사용자 인증을 위해 동일한 토큰을 재사용하는 여러 개의 별도 서버를 가질 수 있음.
- 무상태성(Stateless)
- 토큰에는 사용자를 식별하는 모든 정보가 포함되어 있으므로 세션 상태가 필요하지 않음.
- 이로 인해 확장이 더 쉬움.
JWT란
- JSON 형식으로 웹 요청에 사용하도록 설계된 토큰 구현
- 토큰 자체에서 특정 사용자 관련 데이터를 공유할 수 있으므로 서버 측 세션에서 이러한 세부 정보를 유지·관리하는 부담이 줄어듦
- 각각 마침표로 구분된 3개의 부분으로 구성됨
- Header
- 토큰과 관련된 메타데이터/정보가 저장
- 토큰에 서명하기를 선택한 경우(Signature) 헤더에는 서명을 생성하는 알고리즘의 이름이 포함됩니다.
- Payload
- 나중에 인증(Authentication)과 인가(Authorization)에서 사용할 수 있는 사용자, 역할 등과 관련된 세부 정보를 저장할 수 있습니다.
- 보낼 수 있는 대상이나 양에는 제한이 없으나, 최대한 가볍게 유지하는 게 좋습니다.
- Signature(Optional)
- 토큰을 공유하는 당사자가 내부자이고 신뢰할 수 있지만 웹에서 열 수 없는 경우에는 선택사항일 수 있음
- 그러나 클라이언트가 공개 웹의 불특정한 사용자인 경우 헤더나 페이로드 값을 아무도 변경하지 않았는지 확인해야 합니다.
- 서명 부분을 생성하려면 인코딩된 헤더, 인코딩된 페이로드, 비밀, 헤더에 지정된 알고리즘을 가져와서 서명해야 합니다.
- 서명은 메시지가 도중에 변경되지 않았는지 확인하는 데 사용되며, 개인 키로 서명된 토큰의 경우 JWT를 보낸 사람이 누구인 지 확인할 수 있습니다.
- Header
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
세션이란?
- 전통적으로 많이 사용하던 방식
- 사용자가 로그인에 성공하면, 서버는 세션에 필요한 정보를 저장한다. 반은 사용자의 브라우저로, 반은 메모리로 보낸다.
- 브라우저는 받은 정보를 Session ID라는 이름의 쿠키로 저장하고, 이 브라우저는 앞으로 사이트에서 요청이 들어올 때마다 쿠키를 보냄.
- 이 Session ID가 있으면 로그인 된 상태로 파악하는 것이 세션.
세션 vs JWT
세션 | JWT | |
장점 | 서버 중심 관리: 세션은 서버에서 관리되므로 보안이 뛰어나다. 사용자의 인증 정보나 상태가 서버에 저장되어 클라이언트 측에 민감한 정보가 노출되지 않는다. 세션 만료 및 무효화: 서버에서 세션을 관리하기 때문에 사용자가 로그아웃하거나 일정 시간이 지나면 서버 측에서 세션을 만료시키거나 무효화할 수 있다. 이를 통해 더 나은 보안 관리가 가능하다. 비밀 정보 보호: 서버에서 세션을 관리하기 때문에 민감한 정보를 클라이언트 측에 전달하지 않아도 된다. |
확장성: JWT는 클라이언트가 토큰을 직접 관리하므로, 서버에 세션을 저장할 필요가 없다. 이로 인해 서버의 부하가 줄어들고, 서버 확장이 용이해진다. 서버 간 세션 동기화 문제도 발생하지 않는다. 무상태성: JWT는 무상태(Stateless) 방식으로, 서버는 클라이언트의 상태를 유지할 필요가 없다. 이는 마이크로서비스 아키텍처나 서버리스 환경에서 유리하다. 보안 전송: JWT는 JSON 형태로 인코딩되어 클라이언트와 서버 간에 안전하게 전송할 수 있다. 또한, 필요에 따라 서명(Signature)과 암호화가 가능하다. 다양한 클라이언트 지원: JWT는 다양한 클라이언트와 프로토콜에서 쉽게 사용할 수 있다. RESTful API 등에서 특히 유용하다. |
단점 | 서버 자원 소모: 세션 정보가 서버에 저장되기 때문에 많은 사용자가 접속할 경우 서버의 메모리나 자원을 많이 소모하게 된다. 스케일링 문제: 서버에 세션이 저장되므로 서버를 여러 대로 확장(스케일링)할 경우, 각 서버 간의 세션 동기화가 필요하다. 이를 위해 로드 밸런싱이나 세션 스토리지(예: Redis)를 추가로 설정해야 하는 복잡함이 있다. 쿠키 의존성: 세션 ID가 쿠키에 저장되어 사용되기 때문에, 클라이언트가 쿠키를 비활성화하면 세션 관리에 문제가 발생할 수 있다. |
보안 취약점: JWT는 클라이언트 측에 저장되므로, 토큰이 탈취될 경우 보안 문제가 발생할 수 있다. 토큰 탈취 시 사용자는 로그아웃하거나 만료되기 전까지 계속 인증된 상태로 남는다. 토큰 관리: JWT의 유효 기간이 설정되기 때문에 만료된 토큰을 관리하거나 갱신하는 로직을 구현해야 한다. 이는 추가적인 개발 복잡성을 유발할 수 있다. 토큰 크기: JWT는 세션 ID보다 크기가 크기 때문에 네트워크 트래픽이 증가할 수 있다. 특히 토큰에 많은 클레임(Claims)이 포함될 경우 이 문제가 더 심각해질 수 있다. 로그아웃 처리: JWT는 무상태성이기 때문에, 특정 사용자에 대한 강제 로그아웃 처리가 어렵다. 이를 해결하기 위해 별도의 블랙리스트나 관리 로직이 필요하다. |
어떤 때 세션을 쓰고, 어떤 때 JWT를 써야 하는가?
상대적으로 세션은 보안성과 안정성을 중요시할 때, JWT는 확장성과 효율성을 중요시할 때 사용하는 것이 좋다.
그러나 꼭 세션을 사용해야 하는 경우가 있다면, 세션은 서버에 저장하기 때문에 "일정 기간"동안 로그인 상태로 유지하는 경우이다. (예를 들어 은행 사이트나 자소서 쓸 때 30분만 로그인 유지되고 더 연장하려면 연장버튼을 눌러야 하는 경우)
다른 형태로는 쿠키로 저장하는 형태도 있는데, 쿠키의 경우에는 프로젝트 당시에 다른 팀원 파트에서 쿠키로 정보를 받아와야 할 것이 있어서 그 부분에 한정해서 쿠키를 사용하기도 했었다.
아직까진 너무나도 당연하게 jwt만 생각하고 로그인 관련 구성을 했었는데, 다음 프로젝트를 하게 된다면 나눠야 할 필요가 있어 보인다.