로그인시 JWT 를 어디다 보관해야할지, 어떻게 보관해야 안전할 지 골똘히 생각하다가 정리하는 포스팅..
일단 JWT 를 왜쓰는걸까?
남들이 다 써서^^? 걍 기존 시스템이 jwt라? 위에서 시켜서??
물론 남들이 많이 쓰는덴 다 이유가 있다.
JWT 는 stateless 해서 쓴다. 사용자 정보를 DB에 저장해놓고 요청할때 마다 I/O 해서 검증하는건 stateful 한 방식인 세션방식이다.
On-premise(온-프레미스) → Cloud(클라우드) 시스템으로 넘어가면서 수평적확장(Horizontal Scale Out) 방식을 쓴다.
즉, 사용자가 1000명이었을 땐 서버가 1개였다가 갑자기 급증해서 10000명이 되면 클라우드 플랫폼이 이를 감지하여 서버를 10개 늘리는걸 수평적 확장이라 한다.
이게 stateless 방식을 쓰는 이유중 하나이다.
만약에 Server_1 에서 stateful 인 세션방식을 쓰고 있다고 가정해보자.
그럼 유저1 ~ 유저100 까지의 정보가 Server_1 에서 관리된다.
근데 트래픽이 갑자기 10000명으로 늘어서 서버가 10개로 증가하게 되면?????
Server_2 ~ Server_10 까지는 유저1 ~ 유저100의 정보를 가지고 있지 않다.
그렇다고 유저1~100 까지 Server_1 에 로그인했다면 100명의 정보를 일일이 Server_2 ~ Server_10 까지 동기화 시켜야 하는데, 사실상 어렵고 번거롭다.
그래서 Stateless 방식인 JWT 를 쓰는 것이다.
User ID(사용자정보) + Private Key 를 해싱한 값인 JWT 를 유저에게 보내고,
유저가 Server_1 이든 Server_6 이든 HTTP Request 를 JWT 로 보내면
서버에서는 간편하게 JWT를 다시 복호화하여 equals() 로 비교만 하면된다.
따라서 수평적 확장에 잘 받는 요즘 클라우드 환경에서 유용한 방식인 것이다.
그럼 이 JWT 는 어디다 보관해야 안전할까?...
사실 LocalStorage, SesstionStorage, IndexDB 엄청 많았지만
나는 Nuxt (SSR) 로 진행하고 있었기에 해당사항은 없었다.
그리고 로컬스토리지나 세션스토리지도 자바스크립트로 까면 볼 수 있기 땜시롱 XSS (Cross Site Script) 공격에 취약하다.
(XSS : 스크립트를 통해 html이나 js를 동작시켜 사용자의 인증 정보를 탈취)
특히나 자동로그인 기능 따위를 집어넣게 되는 순간 이 문제는 더욱 골치 아파진다.
(리프레시토큰을 어디다 저장해야하는가...?)
일단 내가 생각한방법은,
1. 로그인시 AccessToken 과 RefrshToken을 발급한다.
AcessToken -> 만료기간이 있는 Cookie나 local_variable 로 생성
RefreshToken -> HttpOnly Secure Cookie
2. 로그인시 통신은 SSL(Https) 로 통신한다.
3. RefreshToken 은 DB에 저장하여 관리한다.(추후 탈취되어도 유효성 체크를 위함)
4. Access-Control-Allow-Origin 설정을 하여 특정 도메인에서 오는 요청만 허용
✔ HttpOnly 옵션을 쓰게되면 일단 스크립트로 접근할 수가 없으므로, XSS 공격엔 안전하다.
Set-Cookie: 쿠키명=쿠키값; path=/; HttpOnly
HttpOnly라는 접미사만 추가함으로써 HTTP Only Cookie가 활성화 되며, 위에서 말한 XSS와 같은 공격이 차단된다. HTTP Only Cookie를 설정하면 브라우저에서 해당 쿠키로 접근할 수 없게 되지만, 쿠키에 포함된 정보의 대부분이 브라우저에서 접근할 필요가 없기 때문에 HTTP Only Cookie는 기본적으로 적용하는 것이 좋다.
HttpOnly 속성은 클라이언트(브라우저 등) 에서 설정할 수 없는 옵션이며, 서버단에서 설정할 수 있는 옵션이다.
https://ssmyefrin.tistory.com/26
하지만 쿠키는 CSRF (Cross Site Request Forgery) 공격엔 취약하다.
(CSRF : 인증된 유저가 의도하지 않게 서버에 공격을 하게 만듬)
이를 막기위해서 HTTPS일 때에만 쿠키를 전송하도록 Secure 옵션을 적용한다.
Set-Cookie: 쿠키명=쿠키값; path=/; secure
또한 쿠키에 담긴 토큰 단독으로 DB 수정/삭제가 되지 않도록 하기위해 나는 토큰마다 권한을 적용시켜 제한을 두었다.
✔ RefreshToken DB 저장
RefreshToken을 탈취당할 경우도 생각한다면 Client가 전달한 RefreshToken의 값과 DB or Redis 휘발성 저장소가 아닌 곳에서 비교하여 맞는지 확인한다면 앞에서 말했 듯 탈취를 당해도 막아낼 수 있다.
아니면 Client 는 인덱스 정보만 저장해놓고 요청시 인덱스를 가지고 DB 데이터와 비교한뒤 토큰을 재발급해도 된다.
쿠키는 브라우저에서 공용으로 사용되기 때문에 악성 사이트에서 접근가능하다. 이 경우 쿠키에 담긴 refreshToken으로 서버에 악성 요청을 보낼수 있는데 이걸 막기위해 CORS 설정을 한다.
CORS 에 대한 개념은 아래 위키에 설명되어있다.
✔ Spring Boot 로 CORS 설정
CORS 설정은 각 부분 별로 할지, 글로벌하게 할지에 따라 세팅방법이 달라진다.
나는 인증시에만 체크할 예정이므로 전자로 진행하겠다
@CrossOrigin(origins = {...})
@CrossOrigin 어노테이션을 통해 CORS 를 설정할 수있다.
결론 :
중요정보를 담고있는 API는 HTTPS 로 보내는게 좋으며,
accessToken 은 유효기간이있는 쿠키나 로컬변수에 저장하고, accessToken 을 재발급받을 수 있는 refreshToken 은 HttpOnly Secure 옵션 쿠키로 발급해서 관리한다.
-끝-
참조 :
https://dncjf64.tistory.com/292
'web > Vue' 카테고리의 다른 글
SPA 와 SSR vs CSR (1) | 2024.02.13 |
---|---|
Nuxt(Vue) 로 admin page 만들기 (2) (0) | 2023.09.05 |
Nuxt(Vue) 로 admin page 만들기 (1) (0) | 2023.09.04 |
Nuxt 구조 (0) | 2023.09.01 |
Nuxt 로 Vue 환경세팅 (0) | 2023.08.31 |