세션의 단점을 보안하기 위해 나온 Token들은 굉장히 다양하다.
우선 기본적으로 토큰은 서버에 요청을 할 때 헤더에 토큰을 함께 보내도록 하면서 유효성 검사를 도와준다. 이러한 시스템에서는 더 이상 사용자의 인증 정보를 서버나 세션에 유지하지 않고 클라이언트 측에서 들어오는 요청만으로 작업을 처리한다. 즉, Stateless 성격을 띄고있다.
장점
- 무상태성 & 확장성 : 토큰은 클라이언트 측에 저장되기 때문에 서버는 완전히 Stateless 하며, 클라이언트와 서버의 연결고리가 없기 때문에 확장하기 매우 적합하다
- 여러 플랫폼 및 도메인 : 서버 기반 인증 시스템의 문제점 중 하나인 CORS 를 해결할 수 있다
토큰을 사용하면 어떤 디바이스, 어떤 도메인에서도 토큰의 유효성 검사를 진행한 후에 요청을 처리할 수있는것이다.
이번엔 그중 JWT(Json Web Token)을 알아보고자 한다.
JWT 는 속성 정보(Claim)를 JSON 데이터 구조로 표현한 토큰이다. 서버와 클라이언트 간 정보를 주고 받을 때 http 리퀘스트 헤더에 JSON 토큰을 넣은 후 서버는 별도의 인증 과정 없이 헤더에 포함되어 있는 JWT 정보를 통해 인증한다.JWT 는 HMAC 알고리즘을 사용하여 비밀키를 사용하거나 RSA를 이용한 Public Key / Private Key 쌍으로 서명에 사용할 수 있다.
JWT 토큰의 구성
JWT 토큰은 크게 3가지의 파트로 이루어져있다. 각 파트는 " . " 으로 구분 되어있고 앞에서 부터 header , payload, signature 로 구성되어있다.
우리가 흔히 보는 Base64 인코딩의 경우 "+", "/", "=" 이 포함되지만 JWT는 URI 에서 파라미터로 사용할수 있는 URL-Safe 한 Base64url 인코딩을 사용한다.
Header
header 에는 토큰의 타입과 어떤 알고리즘을 사용했는지 나온다. 당연히 타입은 JWT 이고 알고리즘은 HS512이다
Payload
payload 에는 보통 Claim이라는 사용자 또는 토큰에 대한 정보들이 key 와 value 상태로 들어간다. 여기에 들어가는 내용은 개발자의 마음이다 어떤 값을 넣어둘지는 제작을 하는 과정에서 정하면 되는것이다.
1. iss( Issuer ) : 토큰 발급자
2. sub( Subject ) : 토큰 제목( 토큰에서 사용자에 대한 식별값이 된다 )
3. and ( Audience ) : 토근의 대상자
4. exp( Expiration Time ) : 해당 토큰의 만료 시간
5. nbf ( Not Before ) : 토큰 활성 날짜 ( 해당 날짜의 이전 토큰들은 활성화하지 않는다)
6. iat ( Issued At ) : 토큰을 발급한 시간
7. jti ( JWT Id ) : JWT 토큰 식별자 ( issure 가 여러명일때 이를 구분한다 )
이건 그저 표준에 불과하고 더 추가하고 싶다면 key 와 value 값으로 추가 할수 있다.
가장 중요한건 Payload 에 민감한 정보를 담지 않는것이다.
위에 보다시피 header 와 payload 는 암호화되는것이 아니다. 그저 디코딩되었을 뿐이다.
?? 아까 위에서는 암호화한다며??
이에 대해 이야기 할것이 있다. 위에서는 Base64url 을 통해 header 와 Payload 모두 암호화 할수 있지만 암호화를 하는것은 생각보다 많은 리소스를 사용하게 된다. 그럼 로그인을 하거나 토큰을 요청하거나 하는 과정에서 복호화가 진행되는것이다 때문에 굳이 암호화를 하지 않고 그저 민감한 정보를 담지 않기로 하는 선에서 마칠수도 있다.
Signature
위에서 본 내용과는 다르게 별 정보가 써있지 않다 물론이다. 여기가 가장 중요한것이다.
your - 256 - bit - secret 이라는 글이 바로 내가 서버에서 사용한 개인키이다.
이뜻은 곧 나의 개인키를 사용해야만 암호화를 풀수 있다는 뜻이고 클라이언트는 임의로 복호화를 진행할수 없다는 뜻이다.
전체적인 복호화를 통한 인증이 진행되는지 알아보자
- JWT 토큰을 클라이언트가 서버로 요청과 동시에 페이로드에 사용할 클레임 데이터를 포함하여 생성하고 전달한다
- 생성된 페이로드는 시크릿 키를 사용하여 signature 를 생성한다. signature는 헤더와 페이로드, 시크릿키를 조합해서 생성된다.
- 서명은 토큰에 추가되어 최종적으로 완성된 JWT 토큰이 되는것이다.
- 그후 만약 JWT가 들어오면 헤더, 페이로드 , 시크릿 키를 사용해서 서명을 재생성한다
- 재생성한 서명과 토큰에 포함된 서명을 비교한다 만약 서명이 일치한다면 토큰의 무결성이 확인되고 만약 다르다면 데이터가 변경되었다는것을 확인하게 되는것이다.
JWT 의 장점
- 임의의 저장소가 필요 없다.
- 세션과는 다르게 상태를 서버에 저장해두지 않는다
- 공통 키 개인키 암호화를 통해 막아두었기 때문에 데이터에 대한 보완성이 늘어난다
- 다른 서비스에 이용할 수 있는 공통적인 스펙으로 사용할 수 있다
JWT 의 단점
- 쿠키와 세션과는 다르게 JWT 는 길이가 길다. 때문에 인증 요청이 증가하면 네트워크의 부하가 생길 수 있는것이다.
- Payload자체에는 암호화가 되지 않기 때문에 유저의 중요한 정보는 담을수 없다.
- 토큰은 한번 발급되면 유효기간이 만료 될때 계속 사용되어 탈취를 당하면 대처가 힘들다.
그렇다면 단점을 보안하기 위해 어떤것을 해야할까?
- 짧은 만료기간 : 토큰의 만료기간을 짧게 성정하여 토큰이 탈취되더라도 빠르게 만료되기 때문에 피해를 최소화 할 수 있다. 그러나 사용자가 자주 로그인을 해야하는 불편함이 수반된다.
- RefreshToken
- 클라이언트가 로그인 요청을 보내면 서버는 AccessToken 및 그보다 긴 만료기간을 가진 RefreshToken 을 발급한다.
- AccessToken 이 만료되었을때 RefreshToken 을 사용하여 AccessToken 의 재 발급을 요청한다. 서버는 DB에 저장된 RefreshToken과 비교하고 유효한 경우 새로운 AccessToken 을 주고, 만료되었을시에 사용자에게 로그인을 요구한다.
- 해당 전략을 사용하면 AccessToken 의 만료 기한을 짧게 설정할 수 있다. 사용자가 자주 로그인 할 필요도 없고 서버가 강제로 RefreshToken 을 만료 시킬수도 있다는 것이다.
- 그러나 검증을 위해 서버는 RefreshToken 을 별도로 저장하고 있어야 하므로 이는 JWT의 장점을 완벽하게 누리지 못한다는 단점이 존재한다.
Reference
'Spring > 👨💻 SpringSecurity' 카테고리의 다른 글
👨💻 JWTFilter 에서 URL의 와일드카드 사용하기(shouldNotFilter) (0) | 2023.08.04 |
---|---|
UsernamePasswordAuthenticationFilter ( feat. FormLogin ) (0) | 2023.06.27 |
ExceptionTranslationFilter 와 RequestCacheAwareFilter (0) | 2023.06.26 |
권한 설정 (0) | 2023.06.26 |
AnonymousAuthenticationFilter (0) | 2023.06.26 |