JWT란?
Json Web Token 의 약자로, 하나의 토큰안에 인증을 위한 정보가 모두 두어 사용자를 인증하는 방식의 수단이다. 인증 방식은 다음과 같다.
엥? 어떻게 그게 인증이 되지?
흐름은 알겠는데 어떻게 JWT자체로 사용자 인증이 가능한지 의문이었다.
사용자가 계속 가지고 있는 토큰만으로 인증이 가능하다면,
위변조를 통해 얼마든지 사용자 인증을 받아낼 수 있지 않을까?
JWT가 어떻게 생성됐는지, 그리고 이를 통해 어떻게 유효한 사용자 요청인지 확인하는 방법을 알면 의문을 해결할 수 있다.
[생성]
[확인]
이를 자바 코드로 구현하면 다음과 같다.
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class Main {
public static void main(String[] args) {
String header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
String payload = "{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022}";
try {
String base64UrlHeader = base64UrlEncode(header);
String base64UrlPayload = base64UrlEncode(payload);
String data = base64UrlHeader + "." + base64UrlPayload;
String secretKey = "my-secret-key";
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] hash_byte = sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));
String signature = Base64.getUrlEncoder().encodeToString(hash_byte);
System.out.println("Signature: " + signature);
} catch (Exception e) {
System.out.println("Error");
}
}
private static String base64UrlEncode(String data) {
String encodedString = Base64.getUrlEncoder().encodeToString(data.getBytes(StandardCharsets.UTF_8));
return encodedString;
}
}
핵심은 서버만 알고 있는 시크릿키와 조합하는 것이다.
만약 사용자가 토큰의 만료기간을 늘리고자 페이로드의 exp값을 조작하여 base64Url로 다시 인코딩하더라도, 서버에서는 변경된 페이로드와 자신의 시크릿키를 조합하여 생성된 새로운 서명이 사용자가 기존에 가지고 있던 서명과 불일치하기 때문에 토큰이 임의로 조작되었음을 알 수 있다.
Session vs JWT
요새는 Session 대신 JWT를 많이 사용하는 추세이다.
본인도 개인프로젝트에서 혼자 프론트와 백엔드를 오가는 고생을 하며 구글링을 하던 와중 JWT를 많이 접하고 필요성을 인지하게 되어 포스팅을 하게 되었다.
그래서 JWT를 적용하기 전 적용해야 하는 이유와 원리를 명확하게 하기 위해 글을 쓰게 되었다.
다음은 Session 대신 JWT를 많이 사용하는 이유이다.
세션 기반의 인증은 사용자 인증 정보를 서버에 저장하는 방식이므로, 여러 서버 사이에서 세션 정보를 공유해야 하는 분산 시스템에서는 문제가 발생할 수 있다. 반면에 JWT는 클라이언트 측에 저장되는 토큰 기반 인증 방식이므로, 이런 환경에서도 쉽게 사용할 수 있다.
세션은 사용자가 많아질수록 서버의 부하가 증가하는 문제가 있다. 반면에 JWT는 클라이언트 측에서 인증 정보를 저장하므로, 서버 부하를 크게 줄일 수 있다. 이는 특히 대규모 시스템에서 중요한 장점이 된다.
모바일 애플리케이션에서는 세션을 관리하는 것이 어려울 수 있다. 모바일 애플리케이션은 브라우저가 아니기 때문에 쿠키를 사용한 세션 관리를 그대로 사용하기 어렵다. 반면에 JWT는 HTTP 헤더에 포함되어 전송되므로, 모바일 환경에서도 쉽게 사용할 수 있다.
JWT는 자체적으로 필요한 모든 정보를 가지고 있다. JWT 토큰 하나로 사용자의 신원, 로그인 정보, 권한 등을 알 수 있다.
세션 쿠키는 동일 출처 정책(Same-Origin Policy)에 의해 한 도메인에서만 사용할 수 있지만, JWT는 크로스 도메인이 가능하므로, 서로 다른 도메인 간에도 인증 정보를 쉽게 전달할 수 있다.
최근 웹 서비스는 REST 아키텍처를 따르는 경향이 있다. REST는 상태 정보를 갖지 않는(Stateless) 특성이 있으므로, JWT와 같은 토큰 기반 인증 방식과 잘 어울린다.
너무 좋은 글이네요. 공유해주셔서 감사합니다.