스프링 시큐리티란 스프링에서는 회원에 대해 권한을 부여하고 이를 통해 보안처리 및 인증을 할 수 있도록 도와주는 JAVA 프레임워크로 대부분의 처음 스프링 시큐리티를 사용하고 적용하는 과정에서는 Form Login 방식을 사용하여 스프링 시큐리티에 인증을 맡기는 방법을 이용하게된다. 하지만 Form Login 방식은 문제가 존재하여 그런 문제를 해결하기 위해 JWT라는 인증 방법이 새롭게 등장하게 된것이다.
우선 이를 설명하기 위한 용어를 이해해야한다.
'인증(Authentication)은 주체(Principal)의 신원(Identify)을 증명하는 과정이다'
스프링 시큐리티를 공부하기 위해 샀던 책에서 나왔던 말로 이말을 풀어서 설명하자면 주체는 사용자를 뜻하며 자신의 신원을 인증받기 위해 Credential을 제시하게되는데 여기서 Credential이란 자신을 사용자라고 증명할 수 있는 수단이며 대부분 회원가입을 할때 사용하는 비밀번호를 사용한다. 신원을 인증 받는다면 사용자에게는 권한(ROLE)을 부여하여주고 권한을 부여받은 사용자는 자신의 권한 범위안의 특정 리소스들을 접근할 수 있다. 이 일련의 과정을 통틀어서 인가(Authorization)이라고 하고 부여되는 권한은 총 4단계가 존재하게 된다.(GUEST<USER<MEMBER<ADMIN). 만약 권한이 없는채로 권한 밖의 리소스를 요청하는 경우 접근통제가 일어난다.
자세한 내용은 아래의 깃허브 TIL을 참고해보자(깃허브홍보는 절대아니다)
https://github.com/seonghoo1217/TodayILearnd/blob/main/Spring-boot/SpringSecurity/SpringSecurity%EC%99%80%20Jwt.md
이러한 구조로 스프링 시큐리티가 작동할 수 있는 이유에는 여러개의 시큐리티 필터가 유기적으로 작동하기 때문이다. 개발자의 입장에서는 커스텀 필터를 사용하지않는다면 어떤 필터가 어떤 작동을 하는지 대부분 알지 못하지만 이번 JWT를 사용하면서 로그인 API를 JSON형태로 Body부분에 받아 처리할 것이기 때문에 커스텀 필터와 여러개의 필터도 함께 살펴볼 예정이다.
이런 부분들은 추후에 코드로 확인하면 이해가 더 빠를 것이라 생각하니 앞서 말하던 Form Login방식대신 왜 JWT라는 대체제를 사용하는지부터 알아보자.
앞서말한 인가 과정을 진행하기 위해 로그인은 필수적으로 진행되어야 하는 과정중 하나이고 이런 로그인 방식은 크게 두가지로 나뉘는데 Session Cookie 방식과 JWT토큰 방식이다. 이때 Form Login방식이 사용하는 방식이 Session Cookie방식인데 사용자에게 고유의 Session ID를 부여하여서 기존의 Cookie만 사용하는 방식보단 안전하지만 세션단에서 사용하기 때문에 세션저장소에 모든 정보를 담아 부하 발생에 대한 대처 및 보안 부분에 있어 문제가 발생된다.
그래서 이러한 세션 쿠키 방법에 한계점을 돌파하고자 나온 방법이 JWT 즉, Json Web Token이다. JWT는 인가에 필요한 정보들을 암호화한 토큰으로 비밀키가 유출되지않는이상 토큰을 복호화하여 사용할 수 없고 만약 복호화된 토큰이 뚫리게 되어도 JWT에는 AccessToken과 RefreshToken이라는 개념이 존재한다. AccessToken은 유효기간이 짧은 토큰으로 이를 가지고 리소스에 접근할 수 있는 토큰이다. 하지만 AccessToken이 뚫리게 되어도 유효기간이 짧기 때문에 탈취에 대비할 수 있다. 그럼 여기서 한가지 의문이 들 수 있다. AccessToken을 보호한다고 유효기간을 짧게 해놓으면 일반 사용자는 어떻게 서비스를 사용하지? 라는 의문이 들것이다. 이를 방지하여 도와주는것이 RefreshToken으로 AccessToken이 만료될때마다 새로 생성해주는 역할을 하며 AccessToken보다 유효기간이 길다.(하지만 이또한 요청이 많으면 부하가 심하다는 단점이 있다.)
또한 JWT는 .을 구분자로 헤더(Header),내용(Payload),서명(signature) 총 3가지로 구분할 수 있다.
1.Header
헤더는 기본적으로 두가지 정보를 담고있다. 바로 typ(토큰의 타입)과 alg(알고리즘)이다.
typ: 토큰의 타입을 지정하며 우리는 JWT를 사용하므로 토큰의 타입은 jwt이다.
alg: 해싱알고리즘을 지정하며 해싱알고리즘으로는 보통 HMAC SHA256 또는 RSA를 사용한다. 알고리즘은 서명부분에서 토큰을 검증할때 사용된다.
2.Payload
페이로드는 토큰에 담을 정보가 들어있다. 정보를 담을 때의 단위를 클레임(Claim)이라고 하며 이는 Name/Value 형태로 저장된다. 또한 토큰에는 여러 Claim을 담을 수 있고 이 프로젝트의 경우 회원정보가 Claim이 될 수 있을것이다.
또한 클레임의 종류는 등록된(registered) 클레임,공개(public) 클레임,비공개(private) 클레임 크게 세가지로 분류된다.
1. 등록된 클레임
등록된 클레임들은 서비스에서 필요한 정보들이 아니라 토큰에대한 정보들을 담기위해 이미 정해진 클레임들을 뜻한다. 등록된 클레임들의 사용은 선택적으로 이루어진다. 등록된 클레임들의 예시로는 다음과 같다
- iss: 토큰 발급자
- sub: 토큰 제목
- aud: 토큰 대상자
- exp: 토큰 만료시간
위의 값들이 가장 대표적으로 사용된다.
2. 공개 클레임
공개 클레임은 클레임이름을 URI형식으로 지정하여 고유한값으로 충돌이 방지되는 용도로 사용된다.
3. 비공개 클레임
등록되지도 않고 공개이지도 않은 클레임들을 뜻하며 클라이언트와 서버간의 협의하에 사용되며 Name:Value형태로 저장하여 사용하는 클레임의 특성상 중복이되어 오류가 날수도 있다.
페이로드 예시
{
"iss": "dain.com",
"exp": "1485270000000",
"https://dain.com/jwt_claims/is_admin": true,
"userId": "13",
"username": "seongho"
}
3. 서명(Signature)
서명은 앞서 말한것과 같이 헤더의 암호화 된 인코딩값과 페이로드의 인코딩값을 합쳐 비밀키로 해싱한 값이 들어갑니다.서명에는 아마 아래와 같은 형태의 값이 나타날것이고 중간에 .으로 헤더와 페이로드를 구분지을 수 있다. 이를 토큰으로 사용할 수 있다.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ2ZWxvcGVydC5jb20iLCJleHAiOiIxNDg1MjcwMDAwMDAwIiwiaHR0cHM6Ly92ZWxvcGVydC5jb20vand0X2NsYWltcy9pc19hZG1pbiI6dHJ1ZSwidXNlcklkIjoiMTEwMjgzNzM3MjcxMDIiLCJ1c2VybmFtZSI6InZlbG9wZXJ0In0.WE5fMufM0NDSVGJ8cAolXGkyB5RmYwCto1pQwDIqo2w
이제 기초적인 스프링 시큐리티와 JWT에 관한 설명을 마쳤으니 다음 단계에서는 코드로 보도록하자.
'Spring-boot' 카테고리의 다른 글
@Getter와 @Setter는 왜 지양되어야 하는가? (0) | 2022.11.29 |
---|---|
[Spring] 패키지 구조 (0) | 2022.10.21 |
[JPA] 비즈니스 로직 디자인 패턴에 관한 정리 (0) | 2022.08.27 |
Web-Socket 공부 흔적(2) STOMP를 사용하는 채팅방[SpringBoot] (0) | 2022.07.09 |
Web-Socket 공부 흔적(1) (0) | 2022.02.23 |