java, spring

[SpringBoot] API Security and JWT

isaac.kim 2022. 3. 15. 20:45
728x90
반응형

[SpringBoot] API Security and JWT

 

이번 글은 API Security와 JWT에 관한 내용에 대해 공부한 내용을 Spring Boot 프로젝트에 적용하기 위한 글이다.

 

목표

1. 토큰을 통한 인증방식의 이해

2. JWT 방식 토큰 인증 구현

 

내용

- 웹 서비스 인증방식 중 하나인 토큰을 이용한 인증방식을 이해한다.

- JWT라는 표준 JSON Web Token을 구현한다.

 

참고 내용

어플리케이션에서 보안은 주로 인증(Authentication)과 인가(Authorization)를 의미하며, Spring Security 프로젝트에서 다루어 진다.

 

아이디/패스워드 기반 인증방식은 최근 더욱 강력한 인증방식인 2단계 인증, 지문과 안면인식을 포함한 하드웨어 인증 방식 등 여러 강력한 인증방식으로 보완/대체되고 있다.

 

Spring Security

스프링 시큐리티는 강력한 인증과 권한 프레임워크

REST API를 인증되고 권한이 있는 요청에만 허락해주는 스프링 보안 관련 프레임워크이다.

 

JWT

보안(인증과 권한)에 많이 사용됨

JWT 토큰 형태로 사용됨

 - URL-safe, 웹브라우저 호환, SSO 지원

 


주요 인증 방식

■ 로그인 기반 인증 (크레덴셜 기반 인증)

 - Credential-based authentication

 - 토큰 기반 인증

 

■ 인증정보를 다른 애플리케이션으로 전달

 - 제 3자가 인증을 처리하는 방식

 - OAuth2

 - Facebook/Google 같은 소셜 계정들을 이용하여 로그인

 

■ 2단계 인증

 - Two-factor authentication

 

■ 하드웨어 인증

 - Hardware authentication


서버 기반 인증 시스템 문제점

■ 세션

 - 유저가 인증할 때 이 기록을 서버에 저장

 - 메모리에 저장 혹은 데이터베이스 시스템에 저장

 - 유저의 수(동시 접속)가 많으면 서버나 DB에 부하

 

■ 확장성

 - 클러스터링 구성 시 세션 정보도 같이 공유해야 함

 - 서버 구성이 복잡해짐

 

■ CORS

 - 쿠키를 여러 도메인에서 관리하는 것이 번거로움

 

 

토큰 기반 인증 시스템 작동 원리

■ 작동원리

  • 유저가 아이디와 비밀번호로 로그인 수행
  • 서버 측에서 해당 정보 검증
  • 계정 정보가 정확하다면 서버 측에서 유저에서 signed 토큰을 발급
  • 클라이언트에서는 토큰을 저장해 두고 요청마다 토큰을 서버에 함께 전달
  • 서버에서 토큰을 검증하고 요청에 응답

 

토큰은 HTTP 헤더에 포함시켜서 전달

 

 

토큰 기반 인증 시스템 - 토큰의 장점

1. 무상태(Stateless)이며 확장성(Scalability)이 있음

2. 보안성

 - 쿠키를 사용하지 않음

 - 토큰 환경에서도 취약점은 존재함

3. Extensibility

 - 서버 확장이 아닌 기능 확장 가능

4. 여러 플랫폼 및 도메인

 - CORS - 아무 도메인에서나 토큰만 유효하면 요청이 정상적으로 처리됨

5. 웹 표준 기반

 - JWT - 토큰 기반 인증 시스템 구현체 (RFC 7519)

 

 

JSON Web Token

■ JWT 특징

 - 웹 표준으로 다양한 프로그래밍 언어에서 지원

   (C, Java, Python, C++, R, JS, GO, Swift ..)

 - Self-contained - 필요한 모든 정보를 자체적으로 가지고 있음

 - 웹 서버의 경우 HTTP 헤더에 넣어서 전달 또는 URL 파라미터로 전달 가능

 

■ JWT 사용되는 상황

 - 회원 인증

 - 정보 교환

 

■ JWT 구조

 - JWT는 . 을 구분자로 3가지 문자열로 구성되어 있다.

aaaaaa.bbbbbb.cccccc

aaaaaa : 헤더(header)
bbbbbb : 내용(payload)
cccccc : 서명(signatrue)

 

 

헤더(Header) - 두 가지 정보를 포함한다.

 

- typ : 토큰의 타입을 지정 (JWT)

- alg : 해싱 알고리즘 지정 (HMAC SHA256, RSA ..)

{
    "typ" : "JWT",
    "alg" : "HS256"
}

 

 

정보(payload)

 

- 토큰에 담을 정보가 포함 (클레임이라고 함, name/value 쌍(key/value)으로 구성)

- 클레임(claim)은 다음 세 분류로 나뉨

 * 등록된 (registered) 클레임 - iss, sub, aud, exp, nbf, sat, jti

 * 공개 (public) 클레임 - 충돌 방지 이름이 필요 (주로 URI 형식으로 네이밍)

 * 비공개 (private) 클레임 - 클라이언트와 서버 간의 협의 하에 사용되는 클레임 이름들

{
    "iss" : "example.com",
    "exp" : "1485270000000",
    "https://example.com/jwt_claims/is_admin" : true,
    "userId" : "11028373727102",
    "username" : "kim"
}

 

 

서명 (signature)

 

- 헤더의 인코딩 값과 정보의 인코딩 값을 합친 후 주어진 비밀키로 해쉬 하여 생성

// 임의로 작성한 값입니다.
eananjkdsnjdk4590sdfi.023i0jfklg.asdklnxcvnkfzcx

. 이 두 개 들어가 있는데 header, payload, signature로 구분되어 있는 것으로 보면 된다.

점(.) 제일 앞에 것은 header, 중간 것은 payload, 두 번째 점(.) 뒤에 것은 signature로 구분

 


라이브러리 설정

Spring Boot 프로젝트에서 Gradle 기반의 라이브러리(library) 관리 툴을 선택하여 다음과 같이 dependency를 설정한다.

dependencies {
	...
	// https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api
	implementation 'javax.xml.bind:jaxb-api:2.3.1'
	// https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt
	implementation 'io.jsonwebtoken:jjwt:0.9.1'
    ...
}

 

구현

SecurityService (interface)

 

createToken : 토큰 생성 메서드

getSubject : 토큰 확인 메서드 (토큰으로부터 정보 확인)

 

SecurityServiceImpl (class)

 

토큰 생성의 구현체 (메서드)

위 메서드에서는 토큰을 발행하는 로직이 담겨있다. 중간에 JwtBuilder 에서 setSubject에서는 정보를 담는다. setExpiration에서는 토큰의 만료시간을 세팅한다.

 

 

토큰 식별의 구현체 (메서드)

토큰 생성에 썼던 key로 토큰을 풀어낸다. (key 파싱 : parseBase64Binary)

 

 

IndexController

토큰을 생성하고, 식별하는 End Point인 Controller Class Code

Controller에서 발행 메서드를 호출할 때 내용과 만료시간을 인자로 넣어 토큰을 발행한다.

 

위 프로젝트 소스 코드를 빌드하고 Postman으로 테스트한다.

 

 

아래 URI로 Token을 발급받는다.

 

http://localhost:8081/security/generate/token?subject=kim

 

발급받은 토큰의 내용을 확인하기 위해 토큰 식별 URI를 호출한다.

http://localhost:8081/security/get/subject?token={tokenValue}

{tokenValue} 값에는 발급 받은 토큰을 넣어서 토큰을 식별한다.

위 이미지를 보면 subject에 입력했던 'kim' 이 return 된 것을 확인할 수 있다.

 

 

jwt.io라는 사이트에서도 해당 토큰을 집어넣고 값을 확인할 수 있다.


 

정리

애플리케이션 보안은 인증과 인가(권한)로 구분되며, 스프링 시큐리티에서 지원한다.

 

JWT 웹 토큰 방식은 인증을 토큰이라는 클라이언트에게 할당되는 스트링을 사용하는 것이며, 웹 표준으로 많은 서비스에서 아용이 늘어나고 있다.

 

 

총평

스프링 시큐리티와 JWT 웹 토큰 인증 방식을 적용하기 위한 사전 학습


오늘은 API Security와 JWT에 대해 알아보았습니다.

도움이 되셨다면 좋아요 꾹! 광고 꾹! 부탁드립니다. 큰 힘이 됩니다. 감사합니다.^^

728x90
반응형