본문 바로가기
Back-end

JWT 토큰

by 신재권 2022. 9. 5.

세션 방식

클라이언트가 서버로 로그인 요청 → 서버 session 생성/유지 → client에게 정보를 응답

서비스 요청 → 서버에서 인증/인가 확인을 위해 세션을 읽음 → 인증/인가 확인 후 응답

문제점

엔터프라이즈 환경에서는 다수의 서버가 존재하고, 각 서버의 세션이 동기화 되어야함 → 데이터베이스에게 부담

쿠키와 세션을 주로 같이 사용하는데 이 떄 CORS(Cross Origin Resource Sharing) 문제가 발생한다. 위 문제들을 해결하기 위한 방안이 Token 이다.

JWT

Spring은 stateless 서비스이다. token을 사용하면 연결을 하지 않은 채로 서비스 제공이 가능하다.

  • token을 사용하면 서버가 늘어나도 인증 방식만 알고있으면 상관없다. → 확장성
  • 쿠키를 전달하지 않기 때문에 취약점이 줄어든다.
  • OAuth 를 통해 다른 서비스에서 로그인 기능을 제공 가능
  • 서버 측의 부담이 덜하다
  • 만료시간을 제대로 설정하면 보안적으로 잘 관리 가능

클라이언트가 로그인 요청 → 서버가 토큰 생성 → 응답 + 토큰 → 클라이언트는 토큰을 가지게 됨 → 서비스 요청 + 토큰 → 서버는 토큰을 기반으로 검증 → 맞으면 서비스 제공

취약점

  • 토큰을 HTTP 헤더에 담아서 전송하기 때문에 스푸닝에 취약
  • 쿠키 방식보다는 보안성이 우수
  • CORS도 해결된다.

토큰의 구성요소

header.

payload. (claims)

signuture

eyJhbGciOiJIUzI1NiJ9. eyJzdWIiOiJ0ZXN0IiwiZXhwIjoxNjYyMzEzMjIxfQ. o-WzLG53-2K8_KsS-JTaJqoBPjhowWUNpJme5HS8_S4

예제 코드

private static final String SECRET_KEY = "asdasdasdsadfasfasdfsadasdasdasdsadasdasdsadasdasdasdsa";

	//로그인 서비스 던질 때 같이
	public String createToken(String subject, long expiredTime) {
		if (expiredTime <= 0) {
			throw new RuntimeException("만료시간이 0보다 커야된다.");
		}

		SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

		byte[] secretKeyBytes = DatatypeConverter.parseBase64Binary(SECRET_KEY);
		Key signingKey = new SecretKeySpec(secretKeyBytes, signatureAlgorithm.getJcaName());

		return Jwts.builder()
			.setSubject(subject)
			.signWith(signingKey, signatureAlgorithm)
			.setExpiration(new Date(System.currentTimeMillis() + expiredTime))
			.compact();
	}

	//토큰검증하는 메서드를 만들어서 boolean 리턴
	public String getSubject(String token) {
		Claims claims = Jwts.parserBuilder()
			.setSigningKey(DatatypeConverter.parseBase64Binary(SECRET_KEY))
			.build()
			.parseClaimsJws(token)
			.getBody();

		return claims.getSubject();
	}

'Back-end' 카테고리의 다른 글

연관관계 매핑 기초  (0) 2022.09.14
엔티티 매핑  (0) 2022.09.07
영속성 관리  (0) 2022.09.02
JPA 시작  (0) 2022.09.01
JPA 소개  (0) 2022.08.31