728x90

개요

스프링 시큐리티를 사용해 로그인/로그아웃을 진행하던 중 기존 방식인 세션 기반 방식의 단점이 있기 때문에 토큰 기반 방식인 로그인 방식을 구현하기로 결정했다. 노션에 정리한 내용을 바탕으로 블로그에 작성한다.!

 

 

0. 시큐리티를 사용한 로그인 방식 종류

  • 시큐리티를 사용한 로그인 방식에는 일반적으로 (1)세션 기반 방식 (2)토큰 기반 방식(JWT) 으로 나뉜다.
  • 두 방식은 어느 것이 더 뛰어나다고 하긴 애매하고, 각 방식의 장단점과 요구사항을 분석하여 상황에 맞게 결정하는 것이 좋다.

1. Spring Security + JWT 동작 원리

Spring Security + JWT 동작 원리

  1. 클라이언트에서 서버로 ID/PW로 로그인을 요청한다.
  2. 서버에서 검증 과정을 거쳐 해당 유저가 존재하면, Access Token + Refresh Token 을 발급한다.
  3. 클라이언트는 요청 헤더에 2번에서 발급받은 Access Token 을 포함하여 API를 요청한다.
  • 여기에서 Access Token과 Refresh Token은 웹 ・ 앱 어플리케이션에서 인증 및 권한 부여를 관리하기 위해 사용되는 토큰이다.

Access Token + Refresh Token 재발급 원리

🖤 Access Token

➡︎ 인증된 사용자가 특정 리소스에 접근할 때 사용되는 토큰

  • 클라이언트는 Access Token을 사용하여 인증된 사용자의 신원을 확인하고, 서비스 또는 리소스에 접근
  • 유효 기간이 지나면 만료 (expired)
  • 만료된 경우, 새로운 Access Token을 얻기 위해 Refresh Token 사용

🖤 Refresh Token

➡︎ Access Token의 갱신을 위해 사용되는 토큰

  • 일반적으로 Access Token과 함께 발급
  • Access Token이 만료되면 Refresh Token을 사용하여 새로운 Access Token 발급
  • 사용자가 지속적으로 인증 상태를 유지할 수 있도록 도와줌 (매번 로그인 다시 하지 않아도 됨)
  • 보안 상의 이유로 Access Token보다 긴 유효 기간 가짐

2. JWT란?

위에서 말한 JWT가 뭔지 보자.

  • JSON Web Token의 줄임말로 JSON 객체로 정보를 주고 받을 때 안전하게 전송하기 위한 방식
  • JSON 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web 토큰이다.
  • JWT는 필요한 정보를 자체적으로 지니는 Self-Contained 방식으로 정보를 안정성 있게 전달한다.
  • 로그인 기능 구현 등에 사용한다.

3. JWT 구조

  • JWT는 Header, Payload, Signature로 이루어져 있으며 각각 점으로 구분한다.
    • ex) xxxxxxx.yyyyyyy.zzzzzzzzz

  • JSON으로 포맷된 각 부분은 Base64로 인코딩되어 표현되며, 각각의 구성 요소는 . 로 구분한다.
  • Base64는 암호화 된 문자열을 반환하는 게 X

3.1. Header

  • 토큰의 헤더는 alg와 typ로 구성된다.
  • Header은 일반적으로 토큰 유형(JWT)과 사용중인 서명 알고리즘(HMAC, SHA256 등)이 포함됨
{
    "typ": "JWT",
    "alg": "HS256"
}
  • alg: 해싱 알고리즘. 서명(Signature) 및 토큰 검증에 사용 (헤더를 암호화 하는 것이 아니고, 서명을 해싱하기 위한 알고리즘 지정)
  • typ: 토큰의 타입

3.2. Payload

  • 토큰의 페이로드에는 토큰에서 사용할 정보의 조각들인 클레임(Claim)이 담겨있다.
  • 클레임은 등록된 클레임(Registered Claim)공개 클레임(Public Claim)비공개 클레임(Private Claim) 으로 나누어지며, key-value 형태로 존재한다.
  • 등록된 클레임(Registered Claim) => 권장되긴 하지만 필수는 아님
    • 등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들로, 모두 선택적으로 작성이 가능하며 사용할 것을 권장한다.
      • iss: 토큰 발급자(issuer)
      • sub: 토큰 제목(subject), unique한 값을 사용한다. 주로 사용자 이메일 사용
      • aud: 토큰 대상자(audience)
      • exp: 토큰 만료 시간(expiration), NumericDate 형식으로 되어 있어야 함 ex) 1480849147370
      • nbf: 토큰 활성 날짜(not before)
      • iat: 토큰 발급 시간(issued at), 토큰 발급 이후의 경과 시간
      • jti: JWT 토큰 식별자(JWT ID), 중복 방지를 위해 사용하며, 일회용 토큰(Access Token) 등에 사용
  • 공개 클레임(Public Claim)
    • 공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해 사용된다. 충돌 방지를 위해 URI 포맷을 이용한다. => 원하는 정보들을 넣으면 됨
  • 비공개 클레임(Private Claim : 개인 클레임**)**
    • 비공개 클레임은 사용자 정의 클레임으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다.
{
    // 등록된 클레임
    "iss": "chb2005.tistory.com",
    "sub": "123456789",
    "exp": "1659002265",
    // 개인 클레임
    "userName": "changbum",
    "isAdmin": false
}

3.3. Signature(서명)

  • 서명(Signature)은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다.
  • 서명은 헤더와 페이로드, 그리고 비밀 키를 기반으로 합쳐 생성된 암호화한 결과값이며, 해당 토큰이 변조되지 않았음을 확인하기 위한 메커니즘이다.
  • [ 서명 생성 과정 ]
    1. 헤더(Header)와 페이로드(Payload)의 값을 각각 BASE64로 인코딩
    2. 인코딩한 값을 비밀 키를 이용해 헤더(Header)에서 정의한 알고리즘으로 해싱
    3. 해싱한 값을 다시 BASE64로 인코딩하여 생성

4. JWT의 장점과 단점

👍🏻 장점

  • auth0을 이용하면 아이디를 카카오, 네이버처럼 다른 사이트에서 이용할 수 있음
  • 서버는 비밀키만 알고 있으면 되기 때문에 세션 방식과 같이 별도의 인증 저장소가 필요하지 않음 => 서버측 부하 감소
  • 서버측 부하를 낮출 수 있고 독립적이기 때문에 능률적으로 접근 권한 관리를 할 수 있고 분산/클라우드 기반 인프라 스트럭처에 잘 대응할 수 있음
  • 여러개의 서버를 사용하는 대형 서비스 같은 경우에 접근 권한 관리가 매우 효율적임 => 확장성이 좋음
  • 별도의 인증 저장소가 필요하지 않아서 인증서버와 db에 의존하지 않아도 됨
  • Refresh Token까지 활용한다면 더 높은 보안성을 가질 수 있음

👎🏻 단점

  • 서버로부터 받은 토큰이 쿠키 또는 로컬스토리지, 세션스토리지에 저장이 되므로 탈취당할 위험이 있으므로 token에 중요 정보를 넣지 않아야 함
  • Payload의 정보(Claim)가 많아질 수록 토큰이 커짐
  • 로그아웃 시 JWT 방식은 세션이 없는 stateless 방식이기 때문에 토큰 관리가 어려움
  • 토큰에 넣는 데이터가 많아질수록 토큰이 길어지는데 API를 호출할 때마다 토큰 데이터를 서버에 전달해야하므로 그만큼 네트워크 대역폭 낭비가 심할 수 있음
  • 한번 발급된 token은 수정, 폐기가 불가 ➡︎ Access token, Refresh token 사용
728x90

+ Recent posts