개발 하나둘셋/Java & Spring

Spring Boot JWT 기본개념과 특징

유리코딩 2021. 12. 10. 02:37
반응형

개념정리

Spring Boot JWT 기본개념과 특징

 

 

1. 서버 기반 인증 vs 토큰 기반 인증

특정 사용자가 서버에 접근을 했을 때, 이 사용자가 인증된 사용자인지 구분하기 위해서는 여러 방법을 사용할 수 있는데, 대표적인 방법으로는

  • 서버 기반 인증
  • 토큰 기반 인증

위 2가지 방법으로 나눌 수 있다. 위 방법들은 각각의 장, 단점이 존재하기 때문에 상황에 맞게 적절한 방법을 선택해야합니다. 그 중 JWT는 '토큰 기반 인증'에 해당하는 방법입니다.

토큰을 사용한다는 것은 요청과 응답에 토큰을 함께 보내 이 사용자가 유효한 사용자인지를 검색하는 방법이다. 이때, 보통 Json Web Token(JWT)를 사용해서 토큰을 전달한다.

 

JWT 동작 방식

출처 : https://velopert.com/2350

 

  1. 클라이언트가 아이디와 비밀번호를 서버에게 전달하며 인증을 요청한다.
  2. 서버는 아이디와 비밀번호를 통해 유효한 사용자인지 검증하고, 유효한 사용자인 경우 토큰을 생성해서 응답한다.
  3. 클라이언트는 토큰을 저장해두었다가, 인증이 필요한 api에 요청할 때 토큰 정보와 함께 요청한다.
  4. 서버는 토큰이 유효한지 검증하고, 유효한 경우에는 응답을 해준다.

 

2. 토큰 사용 방식의 장단점

장점

  • 보안 이슈
    사용자가 자신의 비밀 값으로 서버에 로그인하게 되면, 서버는 JWT를 리턴한다. token을 인증 값으로 사용하게 되면 기존 쿠키/세션을 사용하는 방식보다 많은 보안 이슈를 막을 수 있다. 서버는 GUI로부터 받은 JWT가 유효할 경우, resource를 사용하도록 허용한다. 또한 JWT는 쿠키를 사용하지 않기 떄문에, Cross-Origin Resource Sharing (CORS) 이슈가 발생하지 않는다.  
    • 무상태성 : 사용자의 인증 정보가 담겨있는 토큰을 클라이언트에 저장하기 때문에 서버에서 별도의 저장소가 필요 없어, 완전한 무상태(stateless)를 가질 수 있습니다. 그리고 이로인해 서버를 확장할 때 용이하다.
    • 확장성 : 토큰 기반 인증을 사용하는 다른 시스템에 접근이 가능하다. (ex. Facebook 로그인, Google 로그인)
    • 무결성 : HMAC(Hash-based Message Authentication) 기법이라고도 불리며, 발급 후의 토큰의 정보를 변경하는 행위가 불가능하다. 즉, 토큰이 변조되면 바로 알아차릴 수 있다.
    • 데이터 용량 : JWT는 기존의 XML보다 덜 복잡하고 인코딩 된 사이즈가 작다. 따라서 HTTP와 HTML 환경에서 사용하기 좋다.
    • 사용성 : JSON parser는 대부분의 프로그래밍이 지원하기 때문에 XML을 사용하는 SAML 보다 만들기 쉽다.
    • CORS (Cross-Origin Resource Sharing) 문제 때문에 주로 쓴다.
    • 보안성 : 클라이언트가 서버에 요청을 보낼 때, 쿠키를 전달하지 않기 때문에 쿠키의 한계점을 극복할 수 있다.
Sesstion의 한계
- 서버 확장 시 세션 정보의 동기화 문제
- 서버가 스케일아웃 돼서 여러 개가 생기면 각 서버마다 세션 정보가 저장. 로그인시(서버1), 새로고침(서버2)로 접근하면 서버는 인증이 안됐다고 판단
- 서버 / 세션 저장소의 부하
- 웹 / 앱 간의 상이한 쿠키-세션 처리 로직

 

단점

  • Self-contained : 토큰 자체에 정보를 담고 있으므로 양날의 검이 될 수 있다.
  • 토큰 길이 : 토큰의 페이로드(Payload)에 3종류의 클레임을 저장하기 때문에, 정보가 많아질수록 토큰의 길이가 늘어나 네트워크에 부하를 줄 수 있다.
  • Payload 인코딩 : 페이로드(Payload) 자체는 암호화 된 것이 아니라, BASE64로 인코딩 된 것입니다. 중간에 Payload를 탈취하여 디코딩하면 데이터를 볼 수 있으므로, JWE로 암호화하거나 Payload에 중요 데이터를 넣지 않아야 한다.
  • Stateless : JWT는 상태를 저장하지 않기 때문에 한번 만들어지면 제어가 불가능하다. 즉, 토큰을 임의로 삭제하는 것이 불가능하므로 토큰 만료 시간을 꼭 넣어주어야 한다.
  • Tore Token : 토큰은 클라이언트 측에서 관리해야 하기 때문에, 토큰을 저장해야 합니다.

 

3. JWT 구성

JWT는 .을 기준으로 헤더(header) - 내용(payload) - 서명(signature)으로 이루어져있다.

 

 

3-1. 헤더(header)

헤더는 토큰의 타입과 해싱 알고리즘을 지정하는 정보를 포함한다.

  • typ : 토큰의 타입을 지정합니다. JWT라는 문자열이 들어가게 된다.
  • alg: 해상 알고리즘을 지정합니다.
{
    "typ": "JWT",
    "alg": "HS256" 
}

위 예제를 해석하면, JWT 토큰으로 이루어져있고, 해당 토큰은 HS256으로 해상 알고리즘으로 사용되었다는 것을 알 수 있다

 

3-2. 정보(payload)

토큰에 담을 정보가 들어갑니다. 정보의 한 덩어리를 클레임(claim)이라고 부르며, 클레임은 key-value의 한 쌍으로 이루어져있다. 클레임의 종류는 세 종류로 나눌 수 있다.

  • 등록된(registered) 클레임
    • 토큰에 대한 정보를 담기 위한 클레임들이며, 이미 이름이 등록되어있는 클레임
    • iss : 토큰 발급자(issuer)
    • sub : 토큰 제목(subject)
    • aud : 토큰 대상자(audience)
    • exp : 토큰의 만료시간(expiraton). 시간은 NumericDate 형식으로 되어있어야 하며,(예: 1480849147370) 항상 현재 시간보다 이후로 설정되어있어야한다.
    • nbf : Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념. NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않는다.
    • iat : 토큰이 발급된 시간 (issued at)
    • jti : JWT의 고유 식별자로서, 주로 일회용 토큰에 사용한다.
  • 공개(public) 클레임
    • 말 그대로 공개된 클레임, 충돌을 방지할 수 있는 이름을 가져야하며, 보통 클레임 이름을 URI로 짓는다.
  • 비공개(private) 클레임
    • 클라이언트 - 서버간에 통신을 위해 사용되는 클레임

 

→ 예제 Payload

{
    "iss": "ajufresh@gmail.com", // 등록된(registered) 클레임
    "iat": 1622370878, // 등록된(registered) 클레임
    "exp": 1622372678, // 등록된(registered) 클레임
    "https://shinsunyoung.com/jwt_claims/is_admin": true, // 공개(public) 클레임
    "email": "ajufresh@gmail.com", // 비공개(private) 클레임
    "hello": "안녕하세요!" // 비공개(private) 클레임
}

 

3-3. 서명(signature)

해당 토큰이 조작되었거나 변경되지 않았음을 확인하는 용도로 사용하며, 헤더(header)의 인코딩 값과 정보(payload)의 인코딩값을 합친 후에 주어진 비밀키를 통해 해쉬값을 생성한다.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

 

 

4. JWT 로그인의 이해

  1. JWTAuthFilter : API 요청 Header 에 전달되는 JWT 유효성 인증
    1. 모든 API 에 대해 JWTAuthFilter 가 JWT 확인
    2. 로그인 전 허용이 필요한 API 는 예외처리 필요 ⇒ FilterSkipMatcher
      • ex) 로그인 폼 페이지, 로그인 처리, css 파일 등
  2. FormLoginFilter : 회원 폼 로그인 요청 시 username / password 인증
    1. 인증 성공 시 응답 (Response) 에 JWT 포함
      • JWT 전달방법은 개발자가 정함
      • 예) 응답 Header 에 아래 형태로 JWT 전달
**Authorization: BEARER** <JWT>

ex)
**Authorization: BEARER** eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzcGFydGEiLCJVU0VSTkFNRSI6IuultO2DhOydtCIsIlVTRVJfUk9MRSI6IlJPTEVfVVNFUiIsIkVYUCI6MTYxODU1Mzg5OH0.9WTrWxCWx3YvaKZG14khp21fjkU1VjZV4e9VEf05Hok

 

 

반응형