HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🛁
공부기록
/
🧑🏻‍💻
TIL
/
TIL - 35

TIL - 35

태그
Spring
Security
날짜
May 25, 2022
속성
 

REST API 서비스와 Stateless 아키텍처

  • 앞의 7장까지는 세션을 활용하는 브라우저 웹 기반 서비스에 대해서 시큐리티를 어떻게 활용하는지를 살펴봤다.
  • 지금부터는 SPA(SIngle Page Apllication), 안드로이드/아이폰 모바일 앱 등을 위해 API를 제공하는 API 서버에서 시큐리티를 어떻게 활용할 수 있는지를 알아야한다.
  • 앞서 REST API에 대한 이해가 필요하다 !
 

JWT 알기 전 기본 HTTP 지식

REST API ?

  • API 서비스 개발을 위한 가장 일반적인 접근 방법이다. (사실상 표준 !)
    • 엄격하게 REST API 디자인 원칙을 따르는 것은 쉽지 않다.
    • 통장적으로 REST API로 부르고 있다 — 사회적 통념을 따르자.
  • Java, Python, Go 등 다양한 언어로 풍부한 레퍼런스가 존재한다. - 구현이 쉬움 !
  • HTTP 프로토콜 기반만 따르면 어떤 기술이든 응용이 가능하다.(XML, JSON)
  • 앞에서 알아본 3-Tier Archiecture 구조와 REST API 서비스 궁합이 좋다.
    • 3-Tier Archietecture의 장점 대부분은 REST API 서비스를 개발 및 운영을 할때 유요하다.
  • REST API 서비스에서 Session을 꼭 써야 하는 가에 대해서는 서비스 성격에 따라 고민이 필요하다.
 
notion image
 

Stateful vs Statelsess

  • Stateful 아키텍처의 장단점
    • 세션을 사용하고 있다면 Stateful 하다고 할 수 있다.
    • 앞서 살펴 본 것처럼 수평확장(Scale-Out) 과정이 쉽지 않다. - Session Cluster 반드시 필요
      • Session Cluster의 장애 또는 성능 병목이 서비스 전체에 큰 영향을 줄 수 있다.
    • 단일 사용자의 다중 로그인 컨트롤, 사용자 유효성 체크, 강제 로그아웃 기능 구현이 쉽다.
  • Stateless 아키텍처의 장단점
    • Session을 전혀 사용하지 않아야함 - 사실 HTTP 프로토콜 자체가 Stateless 이기 때문.
    • 수평확장이 매우 쉽다 - Session Cluster 필요가 없다.
    • 단일 사용자의 다중 로그인 컨트롤, 사용자 유효성 체크, 강제 로그아웃 기능 구현이 어렵다.
    • 무엇보다 완전한 Stateless 아키텍처 기반으로 유의미한 서비스 개발이 어렵다.
      • 완전한 Stateless 서비스는 정적 리소스(html, css, js, image)를 서비스 하는데 적합하다. - AWS S3
      • 서버는 어떤식으로는 사용자를 식별할 수 있어야 한다.(단, session 금지)
      •  
 

JWT란 무엇인가?

JWT(Json Web Token)

JWT는 Stateless 상태를 유지하며, 서버에서 사용자를 식별할 수 있는 수단을 제공한다.
  • 서버에서 사용자가 성공적으로 인증되면 JWT를 반환한다.
  • 클라이언트는 JWT를 로컬 영역에 저장하고, 이후 서버에 요청을 보낼 때 JWT를 HTTP 헤더에 포함시킨다.
  • 서버는 클라이언트가 전달한 JWT를 통해 사용자를 식별할 수 있다.
notion image
 

JWT의 개요

  • JSON 포맷을 사용하여 데이터를 만들기 위한 웹 표준(RFC 7519)
  • JWT는 자체적으로 필요한 모든 정보를 지니고 있다.(self-contained)
    • 토큰에 대한 메타정보(토큰타입, 사용된 해시 알고리즘)
    • 사용자 정의 데이터
    • 토큰 유효성 검증을 위한 데이터
  • 인터넷상에서 쉽게 전달할 수 있다.
    • URL-Safe 텍스트로 구성되기 때문에 HTTP 프로토콜의 어느 위치에든 들어갈 수 있다.(보통 HTTP 헤더에 들어감)
    • 위변조 검증이 가능하다.
      • 토큰이 위변조 되지 않았음을 증명하는 서명을 포함한다.

JWT의 구조

  • Header, Payload, Signature 세 부분으로 구성된다.
  • Header, Payload, Signature 세 부분을 Base64 Url-Safe 방식으로 인코딩하고 dot을 구분자로 결합한다.
    • notion image
  • Header - JWT를 검증하는데 필요한 정보를 담고 있다.(토큰 타입, 사용된 알고리즘)
    • 알고리즘은 HMAC, RSA 방식을 지원한다.
    • 아래 그림에서 HS512는 HMAC usin SHA-512를 의미한다.
    • HMAC 알고리즘에서 비밀키는 최소한 알고리즘의 서명 길이만큼의 비트를 가지고 있어야 한다.(HS512 - 64byte)
  • Payload
    • JWT를 통해 전달하고자 하는 데이터 - Claim-Set 이라고도 한다.
      • Caim 자체는 쉽게 말해 key-value 데이터 쌍을 의미한다.
    • JWT 자체는 암호화되는 것이 아니기 때문에 민감 정보를 노출해서는 안된다.
    • Reserved Claims, Public Claims, Custom Claims 로 구분된다.
      • Reserved Claims - 미리 등록된 Claims 필수적으로 사용할 필요는 없지만 사용을 권고한다.
        • iss - 토큰을 발급한 발급자(Issuer)
        • exp - 만료시간이 지난 토큰은 사용 불가
        • nbf - Not Before의 의미로 해당 시간 이전에는 토큰 사용 불가
        • iat - 토큰이 발급된 시각
        • jti - JWT ID로 토큰에 대한 식별자
      • Public Claims - 사용자 마음대로 쓸 수 있으나 충돌 방지를 위해 미리 정의된 이름으로 사용을 권고한다.
      • Custom Claims - 사용자 정의 Claims(Reserved, Public에 정의된 이름과 중복되지 않도록 해야한다.)
      • JSON Web Token (JWT)
        Registration requests should be sent to the mailing list described in [RFC7519].
        JSON Web Token (JWT)
        https://www.iana.org/assignments/jwt/jwt.xhtml#claims
    • Signature
      • 토큰이 생성 주체만 알고 있는 비밀키를 이용해 헤더에 정의된 알고리즘으로 서명된 값
      • 토큰이 위변조 되지 않았음을 증명한다.
      • String concatenated = encodedHeader + '.' + encodedClaims String token = base64URLEncode(hmacSha512(concatenated, key))
         

JWT의 장단점

  • 장점
    • 사용자 인증에 필요한 모든 정보는 토큰 자체에 포함하기 때문에 따로 스토리지가 필요 없다.
      • 수평확장이 매우 쉽다 - Session Cluster 필요없음
    • 따라서, Active User가 많은 서비스에서 JWT 사용이 유리하다.
      • 세션을 사용할 경우 Active User 수 만큼 세션을 저장해야 하기 때문에 스토리지 관리가 어렵기 때문이다.
  • 단점
    • 토큰 크기를 가능한 작게 유지해야 한다.
      • 토큰 자체가 항상 HTTP 요청에 포함되어야 하기 때문에 토큰이 커질수록 불리하다.
    • 유효기간이 남아있는 정상적인 토큰에 대해 강제적으로 만료 처리가 어렵다.
      • 세션을 동시에 사용할 경우 세션제어, 세션 만료처리 등 보안상 이점이 있다.

JWT 찍먹해보자

JWT 의존성 추가하기

<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>${java.jwt.version}</version> </dependency>

JWT yml 설정

server: port: 8080 jwt: header: token issuer: prgrms client-secret: EENY5W0eegTf1naQB2eDeyCLl5kRS2b8xa5c4qLdS0hmVjtbvo8tOyhPMcAmtPuQ expiry-seconds: 60