1. Cookie
클라이언트가 웹사이트에 접속할 때 그 사이트가 사용하게 되는 일련의 작은 기록파일. 서버가 클라이언트에 정보를 전달할 때 저장하고자 하는 정보를 응답 헤더(Cookie)에 저장하여 전달합니다.
쿠키는 간단하게 이야기 하자면 로그인 했을 때 Set-Cookie 형태로 반환을 받은 쿠키를 토대로 로그인이 필요한 요청을 할 때마다 받은 쿠키를 던져 요청하는 동작 구조를 가집니다.
이렇게 쿠키를 사용하는 이유는 어떤 특정 정보를 저장해야 했기 때문입니다. 위 처럼 예를 들어보면 우리는 최초로 ID, PW를 가지고 로그인을 하고 난 이후에는 별 다른 ID, PW 없이 로그인이 된 상태에서 요청을 날릴 수 있습니다. 쿠키가 없었다면 매번 요청을 할때마다 위의 쿠키로 ID, PW를 동시에 사용자가 입력해야 하는 번거로움이 생겼겠죠.
아래와 같은 단점 때문에 쿠키만을 온전히 인증에 사용하지는 않습니다.
- 쿠키는 노출이 되었을 때 id, pw에 대한 민감 정보가 다 노출이 되어 보안성이 떨어진다.
- 쿠키를 조작해 들어올 가능성이 있다.
- 웹 브라우저마다 쿠키에 대한 지원 형태가 다르기 때문에 다른 브라우저간의 공유가 불가능하다.
- 쿠키의 사이즈가 제한 되어 있어(4KB) 원하는 만큼의 충분한 쿠키를 담을 수 없는 경우가 있다.
- 서버는 매번 id, pw를 받아서 인증을 해야하는 불편함이 있으며, 조작된 데이터가 넘어오는 경우를 방지할 수 없다.
2. Cookie & Session
무언가에 대한 특정 인증 정보를 서버가 가지고 있고 그 값을 클라이언트에게 전달하여 마치 키를 주고 자물쇠를 여는 방식으로 인증을 합니다.
세션 ID를 특정 저장소에 저장하여 사용합니다.
개인정보를 그대로 노출했을 때의 단점을 막아내기 위해 등장한 것이 바로 Session 입니다.
사실 쿠키라는 정보 저장체 자체를 주고받는다는 사실은 크게 다르지 않은데, 완전한 새로운 성능의 기술스펙을 구현한 것이 아니라 ID, PW라는 민감정보를 다뤄야 하는 로그인과 같은 상황에서의 보완점을 찾기 위해 나온 것이
Session이기 때문입니다.
아래의 과정으로 인증을 거칩니다
1. 클라이언트가 ID, PW로 서버에 로그인 요청을 한다.
2. 로그인 정보로 인증 후 사용자를 식별할 특정 유니크한 세션 ID를 만들어 마치 열쇠처럼 서버의 세션 저장소에 저장한다.
3. 세션 ID를 특정한 형태(쿠키 또는 JSON) 형태로 클라이언트에게 반환한다.
4. 이후 사용자 인증이 필요한 정보를 요청할 때 마다, 쿠키에 세션ID를 담아 서버에 함께 전달한다.
5. 서버는 이 정보가 세션 저장소에 있는지 확인한다.
완전 쿠키만을 전송할 때와는 다르게 세션 저장소에 식별할 수 있는 값을 넣어두고 그 값이 일치한지 아닌지만 확인하면 인증이 되니 보안성이 올라갑니다
만약 세션 ID 쿠키가 탈취당하는 등 보안문제가 발생하였다면 그냥 세션 저장소를 전부 지워버리면 됩니다. 다르게 이야기 하면 세션 저장소가 다른 모종의 이유로 장애가 난다면 인증 전체가 문제가 생겨 정상적인 사용자가 인증을 하지 못하는 상태가 발생할 수 있습니다.
그럼 쿠키와 마찬가지로 세션의 단점은 아래와 같습니다.
- 세션 저장소의 문제가 발생하면 인증 체계가 무너져 이전에 다른 인증된 유저 또한 인증이 불가해진다.
- stateful 하기 때문에 HTTP의 장점을 발휘하지 못하고 scale out에 대한 걸림돌이 생긴다
- 세션 저장소가 필수적으로 필요하기 때문에 이를 유지하기 위한 비용이 든다.
- 매 요청 시 세션 저장소를 조회해야하는 단점이 있다.
- 서버 사이드에서 세션을 관리하기 때문에 사용자가 많을수록 메모리를 많이 차지한다.
세션을 사용하면서 단점으로 꼽히는 것은 요청을 진행할 때 마다 세션 저장소에 세션 ID를 조회하는 작업을 통해서 DB 접근이라는 로직이 한번 더 수행된다는 점, 이런 과정에서 그럼 이제는 더 좋은 방법이 없을까 하고 등장한 것이 JWT입니다.
3. JWT 토큰
JWT는 JSON Web Token의 약자로 위와 같은 일련의 과정 속에서 나타난 하나의 인터넷 표준 인증 방식입니다. 인증에 필요한 정보를 Token에 담아 암호화시켜 사용하는 방식입니다.
기본적인 인증을 진행하는 방법은 Cookie와 크게 다르지는 않습니다. 다만, 강조되는 점은 JWT는 서명된 토큰이라는 점입니다. 공개/개인키를 쌍으로 사용하여 토큰에 서명할 경우 서명된 토큰은 개인 키를 보유한 서버가 이 서명된 토큰이 정상적인 토큰인지 인증할 수 있다는 이야기입니다.
JWT의 구성요소는 Header, Payload, Signature 세개로 구성되어 있고 각각의 구성요소가 점으로 구분되어 있습니다.
xxxxx.yyyyy.zzzzz
1) Header
{
"typ" : "JWT",
"alg" : "HS512"
}
Header에는 보통의 토큰의 타입이나, 서명 생성에 어떤 알고리즘이 사용되었는지 저장합니다.
지금 같은 경우에는 현재 토큰의 타입이 JWT이고 , 앞서 이야기 했던 개인키로 HS512 알고리즘이 적용되어 암호화가 되어있다고 볼 수 있습니다.
2) Payload
{
"sub" : "JWT",
"iss" : "ori",
"exp" : 1636989718,
"iat" : 1636989718
}
Payload에는 보통 Claim이라는 사용자에 대한, 혹은 토큰에 대한 property를 key-value의 형태로 저장합니다.
말그대로 토큰에서 사용할 정보의 조각입니다. 어떤 Claim값을 넣는지는 개발자의 마음이지만 JWT의 표준 스펙에 대해 알아보도록 하겠습니다.
- iss : 토큰 발급자
- sub : 토큰 제목
- aud : 토큰대상자
- exp : 토큰만료시간
- nbf : 토큰 활성 날짜
- iat : 토큰 발급 시간
- jti : 토큰 식별자
이러한 표준 스펙으로 정의되어있는 스펙이 있다는 것이지, 꼭 이 7가지를 모두 포함해야 하는 것은 아니고 상황에 따라 해당 서버가 가져야 할 인증 체계에 맞게 적용하면 됩니다.
다만 가장 중요한것은 payload에 민감한 정보를 담지 않는것입니다. Header와 Payload는 특별한 암호화가 걸려있지 않기 때문에 누구나 jwt를 가지고 디코딩을 한다면 담긴 값을 알아낼 수 있기 때문입니다.
3) Signatue
가장 중요한 서명입니다. 물론 암호화가 되어 있기 때문에 내부를 알 수는 없습니다. signature는 서버에 있는 개인키로만 암호화를 풀 수 있으므로 다른 클라이언트는 이 부분을 복호화 할 수 없습니다.
복호화 과정은 다음과 같습니다
- JWT 토큰을 클라이언트가 서버로 요청과 동시에 헤더에 담아 전달한다.
- 서버가 가지고 있는 개인키를 가지고 복호화한다음 값을 인증한다.
장점
지금까지 쿠키와 세션을 넘어오며 겪었던 모든 단점을 해결하는 것이 JWT인 것이기 때문에 단점들을 뒤집으면 JWT의 장점이라고 볼 수 있습니다.
- 이미 토큰 자체가 인증된 정보이기 때문에 세션 저장소와 같은 별도의 인증 저장소가 필요하지는 않습니다.
- 세션과 다르게 클라이언트의 상태를 서버가 저장하지 않아도 됩니다.
- signature를 공통 키 개인키 암호화를 통해 막아두었기 때문에 데이터에 대한 보완성이 뛰어납니다.
- 다른 서비스에 이용할 수 있는 공통적인 스펙으로 사용할 수 있습니다.
4. Spring 에서의 JWT
1. JWT 발급받기
먼저 Login 로직을 살펴보면 Login에 필요한 ID, PW를 확이낳는 로직이 필요합니다. DB의 정보와 일치하다면 서버는
사용자의 정보를 넣어 jwt Token을 생성합니다.
2. 스프링 시큐리티 JWT 인증
인증 Filter의 로직을 통해 인증이 필요한 로직의 경우 Token 검증 수행
5. JWT의 단점
- 쿠키, 세션과는 다르게 base64 인코딩을 통한 정보를 전달하므로 전달량이 많다. 따라서 네트워크 전달 시 많은 데이터양으로 부하가 생길 수 있다.
- 토큰이 탈취당하면 만료될 때까지 대처가 불가능하다.
RR
'백엔드 > Spring' 카테고리의 다른 글
[Spring] Spring Validation을 이용한 유효성 검사 (0) | 2024.03.05 |
---|---|
[Swagger] 스웨거(Swagger) Annotation, Validation (0) | 2024.02.28 |
[Spring Security] CSRF 토큰 (0) | 2024.02.26 |
[Spring] Spring IoC 컨테이너, Bean (0) | 2024.01.16 |
[Spring] 필터(Filter)와 인터셉터(Interceptor) (1) | 2024.01.10 |