728x90
개요
스프링 시큐리티를 사용해 로그인/로그아웃을 진행하던 중 기존 방식인 세션 기반 방식의 단점이 있기 때문에 토큰 기반 방식인 로그인 방식을 구현하기로 결정했다. 노션에 정리한 내용을 바탕으로 블로그에 작성한다.!
0. 시큐리티를 사용한 로그인 방식 종류
- 시큐리티를 사용한 로그인 방식에는 일반적으로 (1)세션 기반 방식 과 (2)토큰 기반 방식(JWT) 으로 나뉜다.
- 두 방식은 어느 것이 더 뛰어나다고 하긴 애매하고, 각 방식의 장단점과 요구사항을 분석하여 상황에 맞게 결정하는 것이 좋다.
1. Spring Security + JWT 동작 원리
- 클라이언트에서 서버로 ID/PW로 로그인을 요청한다.
- 서버에서 검증 과정을 거쳐 해당 유저가 존재하면, Access Token + Refresh Token 을 발급한다.
- 클라이언트는 요청 헤더에 2번에서 발급받은 Access Token 을 포함하여 API를 요청한다.
- 여기에서 Access Token과 Refresh Token은 웹 ・ 앱 어플리케이션에서 인증 및 권한 부여를 관리하기 위해 사용되는 토큰이다.
🖤 Access Token
➡︎ 인증된 사용자가 특정 리소스에 접근할 때 사용되는 토큰
- 클라이언트는 Access Token을 사용하여 인증된 사용자의 신원을 확인하고, 서비스 또는 리소스에 접근
- 유효 기간이 지나면 만료 (expired)
- 만료된 경우, 새로운 Access Token을 얻기 위해 Refresh Token 사용
🖤 Refresh Token
➡︎ Access Token의 갱신을 위해 사용되는 토큰
- 일반적으로 Access Token과 함께 발급
- Access Token이 만료되면 Refresh Token을 사용하여 새로운 Access Token 발급
- 사용자가 지속적으로 인증 상태를 유지할 수 있도록 도와줌 (매번 로그인 다시 하지 않아도 됨)
- 보안 상의 이유로 Access Token보다 긴 유효 기간 가짐
2. JWT란?
위에서 말한 JWT가 뭔지 보자.
- JSON Web Token의 줄임말로 JSON 객체로 정보를 주고 받을 때 안전하게 전송하기 위한 방식
- JSON 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web 토큰이다.
- JWT는 필요한 정보를 자체적으로 지니는 Self-Contained 방식으로 정보를 안정성 있게 전달한다.
- 로그인 기능 구현 등에 사용한다.
3. JWT 구조
- JWT는 Header, Payload, Signature로 이루어져 있으며 각각 점으로 구분한다.
- ex) xxxxxxx.yyyyyyy.zzzzzzzzz
- JSON으로 포맷된 각 부분은 Base64로 인코딩되어 표현되며, 각각의 구성 요소는 . 로 구분한다.
- Base64는 암호화 된 문자열을 반환하는 게 X
3.1. Header
- 토큰의 헤더는 alg와 typ로 구성된다.
- Header은 일반적으로 토큰 유형(JWT)과 사용중인 서명 알고리즘(HMAC, SHA256 등)이 포함됨
{
"typ": "JWT",
"alg": "HS256"
}
- alg: 해싱 알고리즘. 서명(Signature) 및 토큰 검증에 사용 (헤더를 암호화 하는 것이 아니고, 서명을 해싱하기 위한 알고리즘 지정)
- typ: 토큰의 타입
3.2. Payload
- 토큰의 페이로드에는 토큰에서 사용할 정보의 조각들인 클레임(Claim)이 담겨있다.
- 클레임은 등록된 클레임(Registered Claim), 공개 클레임(Public Claim), 비공개 클레임(Private Claim) 으로 나누어지며, key-value 형태로 존재한다.
- 등록된 클레임(Registered Claim) => 권장되긴 하지만 필수는 아님
- 등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들로, 모두 선택적으로 작성이 가능하며 사용할 것을 권장한다.
- iss: 토큰 발급자(issuer)
- sub: 토큰 제목(subject), unique한 값을 사용한다. 주로 사용자 이메일 사용
- aud: 토큰 대상자(audience)
- exp: 토큰 만료 시간(expiration), NumericDate 형식으로 되어 있어야 함 ex) 1480849147370
- nbf: 토큰 활성 날짜(not before)
- iat: 토큰 발급 시간(issued at), 토큰 발급 이후의 경과 시간
- jti: JWT 토큰 식별자(JWT ID), 중복 방지를 위해 사용하며, 일회용 토큰(Access Token) 등에 사용
- 등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들로, 모두 선택적으로 작성이 가능하며 사용할 것을 권장한다.
- 공개 클레임(Public Claim)
- 공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해 사용된다. 충돌 방지를 위해 URI 포맷을 이용한다. => 원하는 정보들을 넣으면 됨
- 비공개 클레임(Private Claim : 개인 클레임**)**
- 비공개 클레임은 사용자 정의 클레임으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다.
{
// 등록된 클레임
"iss": "chb2005.tistory.com",
"sub": "123456789",
"exp": "1659002265",
// 개인 클레임
"userName": "changbum",
"isAdmin": false
}
3.3. Signature(서명)
- 서명(Signature)은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다.
- 서명은 헤더와 페이로드, 그리고 비밀 키를 기반으로 합쳐 생성된 암호화한 결과값이며, 해당 토큰이 변조되지 않았음을 확인하기 위한 메커니즘이다.
- [ 서명 생성 과정 ]
- 헤더(Header)와 페이로드(Payload)의 값을 각각 BASE64로 인코딩
- 인코딩한 값을 비밀 키를 이용해 헤더(Header)에서 정의한 알고리즘으로 해싱
- 해싱한 값을 다시 BASE64로 인코딩하여 생성
4. JWT의 장점과 단점
👍🏻 장점
- auth0을 이용하면 아이디를 카카오, 네이버처럼 다른 사이트에서 이용할 수 있음
- 서버는 비밀키만 알고 있으면 되기 때문에 세션 방식과 같이 별도의 인증 저장소가 필요하지 않음 => 서버측 부하 감소
- 서버측 부하를 낮출 수 있고 독립적이기 때문에 능률적으로 접근 권한 관리를 할 수 있고 분산/클라우드 기반 인프라 스트럭처에 잘 대응할 수 있음
- 여러개의 서버를 사용하는 대형 서비스 같은 경우에 접근 권한 관리가 매우 효율적임 => 확장성이 좋음
- 별도의 인증 저장소가 필요하지 않아서 인증서버와 db에 의존하지 않아도 됨
- Refresh Token까지 활용한다면 더 높은 보안성을 가질 수 있음
👎🏻 단점
- 서버로부터 받은 토큰이 쿠키 또는 로컬스토리지, 세션스토리지에 저장이 되므로 탈취당할 위험이 있으므로 token에 중요 정보를 넣지 않아야 함
- Payload의 정보(Claim)가 많아질 수록 토큰이 커짐
- 로그아웃 시 JWT 방식은 세션이 없는 stateless 방식이기 때문에 토큰 관리가 어려움
- 토큰에 넣는 데이터가 많아질수록 토큰이 길어지는데 API를 호출할 때마다 토큰 데이터를 서버에 전달해야하므로 그만큼 네트워크 대역폭 낭비가 심할 수 있음
- 한번 발급된 token은 수정, 폐기가 불가 ➡︎ Access token, Refresh token 사용
728x90
'Spring > Security' 카테고리의 다른 글
Spring Security + Session 를 사용한 회원가입, 로그인, 로그아웃 구현 (0) | 2024.07.26 |
---|---|
Spring Security : SecurityConfig 설정 정리 (2) | 2024.07.23 |
Spring Security + JWT (RefreshToken, AccessToken)를 사용한 로그인, 로그아웃 구현 - 4편 (0) | 2024.07.23 |
Spring Security + JWT (RefreshToken, AccessToken)를 사용한 로그인, 로그아웃 구현 - 3편 (1) | 2024.07.22 |
Spring Security + JWT (RefreshToken, AccessToken)를 사용한 로그인, 로그아웃 구현 - 2편 (1) | 2024.07.22 |