본문 바로가기

Language/Spring

[Authentication] Cookie, Session, JWT Token

인증 / 인가

  • 인증(Authentication)
    • 사용자의 신원을 확인하는 과정
    • Ex) ID, PW를 이용한 로그인 / 생체 인식(지문, 얼굴) / OTP / 인증서 등

 

  • 인가(Authorization)
    • 인증 이후의 프로세스로 인증된 유저가 어떠한 자원에 접근할 수 있는 지 확인하는 프로세스
    • Ex) 관리자 페이지 - 관리자 권한을 가진 유저만 접근 가능


웹 애플리케이션 인증의 특수성

  • 일반적으로 서버 - 클라이언트 구조
  • Http 프로토콜을 이용한 통신
    비연결성(Connectionless), 무상태(Stateless)의 특징을 가짐

 

비연결성(Connectionless)
  • 서버와 클라이언트가 연결되어 있지 않음
  • 서버와 클라이언트가 계속 연결되어 있다면, 서버의 비용이 기하급수적으로 증가
  • 리소스의 절약을 위해 서버는 하나의 요청에 하나의 응답을 보내고 연결 종료

 

무상태(Stateless)
  • 서버가 클라이언트의 이전 상태를 저장하지 않음
    → 따라서, 클라이언트가 직전에 무슨 요청을 보냈었는지 알 수 없음
  • 기존의 상태를 저장하는 것은 서버의 비용과 부담을 증가시키기 때문에, 기존의 상태가 없다고 가정하는 프로토콜을 구현
  • 이를 해결 하기 위해 클라이언트가 필요한 상태 정보를 매번 서버로 전송
    → 쿠키, 세션, 토큰을 활용

웹 애플리케이션의 인증 방식

  • Http의 Connectionless와 Stateless라는 특성을 생각해보면, 사용자가 로그인을 통해 인증을 거쳐도 이후 요청에 대해서는 인증된 상태를 유지 불가
  • 서버가 사용자가 로그인을 했다는 정보를 저장하지 않기 때문에, 최초 로그인 이후 매 요청마다 반복적으로 ID, PW를 입력하여 인증을 받고 페이지에 접근이 가능한지 인가를 받아야 함
  • 하지만, 우리는 웹 어플리케이션을 이용할 때 로그인을 한 번 하면 그 이후에 반복해서 로그인 하지 않아도 회원이 접속 가능한 페이지에 접근이 가능

쿠키(Cookie)

  • 클라이언트에 저장되는 작은 데이터 파일
  1. 사용자 로그인 시도
  2. 서버에서 DB에 있는 정보와 비교하여 확인
  3. 서버는 Cookie를 생성하여 클라이언트에게 전송
  4. 이후 브라우저는 서버에서 받은 쿠키를 저장하고 동일한 서버로 재요청할 때 쿠키를 함께 전송
    → 클라이언트가 요청할 때마다 서버는 로그인 정보가 담긴 쿠키를 받아 확인하고 요청에 대한 응답

 

쿠키의 장점
  • 클라이언트 측에 저장이 되는 데이터이기 때문에 서버의 부담이 감소

 

쿠키의 단점
  • 사용자의 주요 정보를 매번 요청에 담기 때문에 보안상 문제가 발생
  • 클라이언트에서 쿠키 정보를 쉽게 변경, 삭제, 탈취 가능
    • 단, 쿠키의 보안 속성을 통해 일부 위험 완화 가능
      • HttpOnly : 쿠키가 자바스크립트에서 접근되지 않도록 하여 XSS 공격을 방지
      • Secure : HTTPS에서만 쿠키를 전송하도록 설정하여 안전한 통신을 보장
      • SameSite : 쿠키의 크로스사이트 요청을 제한해 CSRF 공격을 방지
  • 쿠키 사이즈가 커질수록 네트워크 부하가 발생

 

쿠키의 구성 요소
  • Name(이름)
    • 쿠키를 구별하는 데 사용되는 키 (식별자, Unique)
  • Value(값)
    • 쿠키의 값
  • Domain(도메인)
    • 쿠키가 저장된 도메인
  • Path(경로)
    • 쿠키가 사용되는 경로
  • Expires(만료기한)
    • 쿠키의 만료기한

세션(Session)

  • 서버에서 일정시간 동안 클라이언트 상태 유지하기 위해 사용
  • 서버에서 클라이언트별 유일한 세션 ID를 부여하고, 세션 정보를 서버에 저장
    • Session ID : 사용자의 주요 정보가 아닌, 단지 사용자를 식별할 수 있는 값을 생성
      → 보안 강화
  1. 사용자 로그인 시도
  2. 서버에서 DB에 있는 정보와 비교하여 확인
  3. 회원 정보에 대한 세션 생성
  4. Session ID를 클라이언트에게 쿠키로 전송
  5. 클라이언트에서 어떠한 요청을 보낼 때 세션 쿠키를 함께 요청
  6. 서버의 세션 저장소에는 클라이언트별 세션 쿠키 값이 저장되어 있어 요청으로 온 세션 ID를 기반으로 어떤 클라이언트인지 식별 가능

 

세션의 장점
  • 사용자의 로그인 정보를 주고 받지 않기 때문민감한 정보의 노출 위험 감소
  • 사용자마다 고유한 세션 ID가 발급되기 때문에 요청이 들어올 때마다 회원DB를 찾지 않음
  • 인증된 사용자 정보를 서버 메모리나 세션 저장소에서 직접 조회하기 때문에 DB 부하 감소

 

세션의 단점
  • 사용자를 식별할 수 있는 값인 세션 ID를 생성하고 서버에 저장하는 작업 발생
    서버 메모리나 데이터베이스, Redis 같은 저장소에 저장되기 때문에 서버의 리소스를 차지
  • 서버 세션 저장소를 사용하므로 요청이 많아지면 서버의 부담이 증가
    많은 사용자가 동시에 접속하면 세션 저장소의 용량과 성능이 이슈
    • 이를 해결하기 위해 세션을 분산 서버에서 관리하거나 외부 캐시 저장소(예: Redis)를 사용하는 방식을 도입 가능

JWT(JSON Web Token)
  • 인증에 필요한 정보들을 암호화시킨 토큰
  • JWT 토큰(Access Token)을 HTTP 헤더에 담아 인증된 사용자임을 확인하는 데 사용
    JWT 자체는 사용자 식별뿐만 아니라 권한 정보, 유효 기간 등의 인증 정보를 포함
  • 클라이언트 측에 저장하여 서버의 부담 감소

 

JWT 구조
  • Header
    • 토큰 타입, 해쉬 알고리즘(HS256 or RSA 등)으로 구성
{
  "alg": "HS256",
  "typ": "JWT"
}

 

  • Payload 
    • 클라이언트 고유 ID 값이나 유효 기간 등이 포함되는 영역
    • claim이 포함되는 영역으로 3가지로 나뉨
      토큰에 담을 정보를 가짐
      • 등록된 클레임(Registered Claim) : iss(발행자), exp(만료 시간), sub(주제), aud(대상자)와 같은 표준 클레임
      • 공개 클레임(Public Claim) : username, role 등 개발자가 정의하는 클레임
      • 비공개 클레임(Private Claim) : 특정 서비스나 사용자 간의 정보로, 개발자가 자유롭게 정의할 수 있는 클레임
{
  "sub": "1234567890",
  "username": "user1",
  "admin": true
}

 

  • Signature
    • 인코딩된 Header와 Payload를 더한 뒤 secret key로 해싱해서 생성
      이 때, 해싱 방법은 Header에서 지정한 해쉬 알고리즘을 사용
    • Header와 Payload는 단순히 인코딩된 값이어서 누구든 복호화가 가능하지만, Signature는 서버 측에서 관리하는 secret key가 있어야 복호화가 가능
    • Signature 부분으로 토큰의 위변조 여부를 확인 가능
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)

 

JWT의 동작 과정

  1. 클라이언트가 ID, PW 로그인 요청
  2. 서버에서 DB에 있는 정보와 비교하여 확인
  3. 로그인 성공 시 서버는 로그인 정보를 Payload에 담고, Secret Key를 사용해서 Access Token(JWT)을 발급
  4. 서버가 JWT를 클라이언트에 전달
     전달방법은 개발자가 결정
    ex) 응답 Header에 Authorization: BEARER <JWT> 형태로 전달
  5. 클라이언트는 전달받은 토큰(JWT)을 저장 ( 쿠키, 로컬 스토리지, 세션 스토리지 등)
      쿠키에 저장하는 경우에는 HttpOnly와 Secure 속성을 설정해 보안 강화 가능
  6. 클라이언트가 서버에 요청할 때마다 토큰(JWT)을 요청 Header의 Authorization에 포함시켜 함께 전달
  7. 서버는 클라이언트가 전달한 토큰의 Signature를 secret Key로 복호화한 후, 위변조 여부 및 유효기간을 검증
  8. 검증에 성공하면 JWT에서 사용자 정보를 확인하고 요청에 응답

 

JWT 장점
  • 동시 접속자가 많을 때 서버 부하 감소
  • 클라이언트, 서버가 다른 도메인을 사용할 때 사용 가능
    ex) 카카오 OAuth2 로그인 시 JWT 토큰 사용
    Cross-Origin 상황에서도 사용할 수 있어, OAuth2 같은 외부 인증에서도 널리 사용
  • 인증 정보를 서버에 별도로 저장하지 않음
    → 서버의 Stateless 특성 유지

 

JWT 단점
  • 구현 복잡도 증가
  • JWT에 담는 내용이 커질수록 네트워크 비용이 증가
    JWT는 매 요청마다 전송되기 때문Payload가 크면 네트워크 부하가 증가
  • 이미 생성된 JWT를 일부만 만료 불가
    → JWT는 발급된 이후에는 토큰 자체 수정이 불가하여 특정 사용자만 로그아웃 시키는 등의 세부적인 제어가 어려움
  • Secret Key 유출 시 JWT 조작이 가능
  • Payload 자체는 암호화되지 않기 때문에 사용자의 중요한 정보 저장 불가
    Payload는 Base64 URL로 인코딩된 것이지 암호화된 것은 아니므로, 중요한 정보는 JWT에 직접 담으면 안 됨
보충 내용
  • JWT의 갱신(Refresh Token)
    • Access Token이 만료되었을 때 새로운 토큰을 발급받기 위해 Refresh Token을 함께 사용하는 전략
    • Refresh Token은 주로 서버에 저장되며 이를 통해 Access Token을 갱신
  • JWT의 만료 시간 설정
    • JWT의 유효기간 설정 매우 중요
    • 너무 길게 설정하면 보안 문제가 생기고, 너무 짧게 설정하면 사용자가 자주 재인증

 

참고 자료

쿠키, 세션, JWT에 대해 알아보자 : https://velog.io/@kimdy0915/%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D%EC%BF%A0%ED%82%A4-%EC%84%B8%EC%85%98-JWT%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90