본문 바로가기
Nodejs

[Nodejs] 쿠키와 세션 인증 그리고 JWT

by hotdog7778 2023. 10. 21.

1. http의 특징

  • 비연결성 : 클라이언트에 대한 서버의 응답 이후 연결을 끊는것 성질
  • 무상태성 : 클라이언트의 상태를 저장하지 않는 성질

http 특징에 따라 서버는 매 요청마다 클라이언트를 식별할 수 가 없는것.

요청1) 클라이언트 --로그인 요청--> 서버  / OK 로그인해

요청2) 클라이언트 --마이페이지 보여줘--> 서버 / 너가 누군데

 

그래서, 클라이언트의 상태를 기억해야할 필요성이 생긴 것임. (예를 들어 로그인 유지)

 

클라이언트와 서버에서 어떤 방식으로 데이터를 유지하고 상태관리를 할 수 있는지에 대해서 쿠키/세션/JWT 에 대해 학습하고 정리하기.

 

 

2. 쿠키

 

특징

 - 클라이언트에 저장되는 데이터 조각(텍스트 파일)

 - 키-밸류 쌍으로 웹 서버에서 생성, 클라이언트 브라우저에 저장

 - 쿠키는 HTTP 요청 및 응답 헤더를 통해 전달 (요청: Cookie 필드, 응답: Set-Cookie 필드에 저장)

 - 암호화 없이 텍스트형식으로 저장됨

 

 

보안 취약점

 - 쿠키 유출/조작 가능

 

 

보완 방법

 - HttpOnly 쿠키: HttpOnly 속성이 설정된 쿠키는 JavaScript를 통해 액세스할 수 없으므로 XSS 공격으로부터 보호할 수 있음.

 - HTTPS 사용: 중요한 정보를 포함하는 쿠키를 전송할 때 HTTPS 연결을 사용하면 클라<->서버 통신시 중간에서 데이터를 인터셉트하거나 엿보는 것을 방지할 수 있음.

 - Secure 쿠키: Secure 속성이 설정된 쿠키는 HTTPS 연결에서만 전송되므로 중요한 정보를 포함하는 쿠키에 이 속성을 적용

 

 

3. 쿠키 and 세션

 

특징

 - 세션은 클라이언트의 상태를 관리하기위해 서버에서 생성하고 저장하는 데이터.

 - 세션은 쿠키에 담겨서 클라이언트로 배달된다. 데이터는 제외하고 세션 ID만 배달됨

 - 클라이언트 <-> 서버 간 세션ID를 주고 받는데, 세션 ID가 유효한지 검증은 서버에서 한다.

 - 서버측에서 세션 데이터를 저장하는 Store를 지정할 수 있다. (redis,mysql,mongodb 등)

 - 세션 데이터를 저장소에 저장하는 과정에서 서버의 부하가 발생 할 수 있음

 

 

보안 취약점

 - 쿠키 속 세션ID 자체는 유의미한 개인정보가 아니지만 이것을 탈취해서 주인인척 위장할 수 있음(JWT도 똑같음)

 - HTTPS나 HttpOnly, Secure 속성을 사용해서 쿠키자체의 보안을 강화 한다.

 - 서버에서 세션의 검증 로직을 추가한다. (ex. 클라이언트 IP 주소나 사용자의 에이전트 정보를 활용)

 

 

4. JWT(Json Web Token)

 

특징

 - 인증에 필요한 정보를 클라이언트 측에서 토큰으로 저장한다.

 - 서버는 토큰의 변조가 이루어졌는지 검증 후 권한을 준다.

 - 헤더.페이로드.서명 과 같은 구조를 가진다.

 - 페이로드에 데이터가 들어있으며, 노출되는 데이터이기 때문에 민감한 정보를 담으면 안된다.

 - 토큰에 내용물(데이터)가 들어있으므로 용량이 클 수 있다. (매번 요청마다 토큰이 오가는 데이터 비용에대해 생각할것)

 

 

저장 방식

 - 토큰은 클라이언트측에서 저장된다.

 - 쿠키에 저장 : 쿠키는 일반적으로 자동으로 모든 HTTP 요청에 포함 된다.

 - localStorage 에 저장 : 브라우저의 로컬 스토리지에 토큰을 저장

※ 두가지 외에도 방법은 더 있고, 쿠키와 localStorage에 저장하는것 둘다 각각의 보안 취약점이 존재함

 

 

전달 방식

 - 일반적인 방법 : Authorization 헤더를 사용해서 전달.

 - 쿼리의 매개변수 혹은 본문(body)에 포함시켜서 전달할 수도 있음.

 

서명을 생성하고 확인하는 방식

 1. 서명 생성 :

     - 헤더와 페이로드를 Base64로 인코딩한 문자열 준비 (Header.Payload 형태)

     - 헤더에 지정된 해시 알고리즘으로 시크릿 키와 함께 해싱한다.

 2. 서명 추가 : 

     - 생성된 서명을 Header.Payload 에 추가하여 "Header.Payload.Signature"의 형태로 JWT를 완성한다.

 3. JWT를 주고 받다가 검증 : 

     - 수신측(예를들면 서버) 에서 JWT를 받는다.

     - 받은 JWT의 Header.Payload 를 동일한 해시 알고리즘과 시크릿키를 사용해서 서명을 재생성한다.

     - 재생성한 서명과 받은 JWT의 서명이 일치하는지 비교한다. (토큰내용에 변경이 없다면 일치해야겠죠)

 

 

보안 취약점

 - JWT가 탈취되면 해당 토큰을 가로챈 사람이 해당 세션 또는 사용자의 역할을 위장할 수 있다.

 - JWT의 만료 시간(Expiration Time, exp)을 정확하게 관리하지 않으면, 토큰이 무제한으로 보존될 수 있어 보안에 취약


보완 방법

 - 서버에서 JWT 검증 로직을 추가한다. (ex. 클라이언트 IP 주소나 사용자의 에이전트 정보를 활용)

 - 쿠키로 JWT를 보관 및 전달한다면 쿠키 자체의 보안을 강화해야 한다.

 - Access Token / Refresh Token 전략 사용

 

 

 

 Refresh Token
클라이언트가 로그인 요청을 보내면 서버는 Access Token 및 그보다 긴 만료 기간을 가진 Refresh Token을 발급하는 전략입니다. 클라이언트는 Access Token이 만료되었을 때 Refresh Token을 사용하여 Access Token의 재발급을 요청합니다. 서버는 DB에 저장된 Refresh Token과 비교하여 유효한 경우 새로운 Access Token을 발급하고, 만료된 경우 사용자에게 로그인을 요구합니다.

해당 전략을 사용하면 Access Token의 만료 기한을 짧게 설정할 수 있으며, 사용자가 자주 로그인할 필요가 없습니다. 또한 서버가 강제로 Refresh Token을 만료시킬 수 있습니다.

그러나 검증을 위해 서버는 Refresh Token을 별도의 storage에 저장해야 합니다. 이는 추가적인 I/O 작업이 발생함을 의미하기 때문에 JWT의 장점(I/O 작업이 필요 없는 빠른 인증 처리)을 완벽하게 누릴 수 없습니다. 클라이언트도 탈취 방지를 위해 Refresh Token을 보안이 유지되는 공간에 저장해야 합니다.

 

 

https://velog.io/@0307kwon/JWT%EB%8A%94-%EC%96%B4%EB%94%94%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C-localStorage-vs-cookie

https://tecoble.techcourse.co.kr/post/2021-05-22-cookie-session-jwt/