로그인을 구현해본 개발자라면 경험해 본적 있을것!
Web Storage 웹스토리지
키/값을 쌍으로 데이터를 저장하고, 키를 기반으로 데이터를 조회하는 패턴이다.
브라우저에 저장해야하는 데이터, 즉 클라이언트에서 수시로 변경되는 데이터를 웹 스토리지에 저장하게 된다.
DB 를 사용하지 않고, 데이터를 임시적으로 저장할때 사용하는 곳이라고 이해하면 된다.
- 저장된 데이터가 존재할 뿐, 서버로 전송하지 않는다. 네트워크 트래픽 비용을 줄여준다.
- 서버에 전송하는 법 : js로 스토리지의 데이터를 읽고, 명시적으로 서버에 전송한다.
- 용량의 제한이 없다
- 한번 저장하면 영구적으로 존재한다.
- 보안적인 문제가 될 수 있다.
- LocalStorage, Session Storage 가 존재하며, 데이터의 지속성에 따라 제공된다
- 탭/창 마다 공유할 데이터는 localStorage에, 개별데이터는 SessionStorage 에 저장한다.
EX) 글 임시저장, 쇼핑몰 장바구니, 좋아요 콘텐츠 등
개발자도구 > Application 어플리케이션 > 좌측 Storage 저장용량 탭
에서 확인할 수 있다.
LocalStorage 로컬스토리지
- 저장한 데이터를 지우지 않는 이상, 영구적으로 보관된다. = `시간 제한 없음`
- 브라우저를 종료해도, 데이터가 유지되어 다음 접속에서도 데이터를 그대로 사용할 수 있다.
- 도메인마다 별도의 로컬스토리지가 생성된다.
- 동일한 Origin을 가진 프로토콜, 도메인, 포트를 공유하는 모든 탭/ 윈도우에 전역적으로 공유 가능하다.
- http, https 는 다른 스토리지로 구분됨
- 문자열, JS object 객체 - 저장 가능하다.
삭제??? removeItem 또는 개발자도구에서 🚫 표시를 누르면 지워진다. 즉, 직접 지워줘야한다.
또는 브라우저나 운영체제에 의해 자동으로 지워지는 경우가 있다고 한다.
localStorage.setItem("accessToken", "datdaradanadat"); // 저장 (키, 값)
localStorage.getItem("accessToken"); // datdaradanadat
localStorage.removeItem("accessToken"); // accessToken 키 삭제
localStorage.clear(); // 전체 삭제
EX) 개인화 : 사용자 선호, 테마 등의 세팅, 사용자 정보
장점 : 용량이 커서 (5~10MB), 큰 데이터도 저장가능
단점
- HTML5 이전 브라우저는 작동하지 않는다.
- 암호화 같은 보안 기능 제공하지 않는다.
- 민감한 데이터 저장금지
그럼 데이터 보안이 필요한 경우에는???
- 서버 측 세션 스토리지
- HTTPS를 통한 데이터 전송
- 데이터 암호화
등 추가적인 보안 조치를 적용해야 한다.
SessionStorage
- 세션을 종료할때 클라이언트에 대한 정보가 삭제된다
- 세션 session
- 일반적으로 세션의 종료는 브라우저의 종료라고 하지만,
- 세션 스토리지의 세션 : 가장 작은 단위인 탭단위
- 현재 페이지가 브라우징 되고있는 브라우저 컨텍스트 내에서만 데이터가 유지된다.
- 즉, 탭/창 각각 별개의 영역으로 구분하고, 서로 침범할 수 없다.
- 탭/창 을 닫으면 (페이지 세션 끝날때) 데이터가 삭제된다.
- 즉, 휘발성 데이터를 저장할대 사용한다.
- 동일한 Origin을 가진 프로토콜, 도메인, 포트로 구분한다.
- 세션 session
- 문자열, JS object 객체 - 저장 가능하다.
- cookie 문제점 - '도메인이 같으면 항상 쿠키를 보낸다'는 조건을 해결한 것.
- 간혹 세션스토리지가 쿠키에 기반을 두고있다고 하는데, 틀린말이다.
- 브라우저 기반 세션 쿠키와 비슷한 성질이다.
- 일정 기간 후 삭제된다는 부분이 보안 측면에서 유리하다
EX) 일회성 로그인, 입력 폼 저장 등
sessionStorage.setItem("accessToken","datdaradanadat"); // 저장 (키, 값)
sessionStorage.getItem("accessToken"); // datdaradanadat
sessionStorage.removeItem("accessToken");
sessionStorage.clear( );
장점 : 용량이 커서 (5~10MB), 큰 데이터도 저장가능
단점 : HTML5 이전 브라우저는 작동하지 않는다.
HTTP Cookie 쿠키
HTTP 쿠키 : 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각 (4KB)
클라이언트에 대한 정보를 사용자 PC의 하드디스크에 보관하기 위해서
웹 사이트(서버)에서 클라이언트의 웹 브라우저에 전송하는 정보
클라이언트는 쿠키를 저장해 두었다가, 동일한 서버에 HTTP 재요청 시 저장된 데이터를 함께 전송한다.
쿠키는 두 요청이 동일한 클라이언트에서 들어왔는지 아닌지를 판단할때 사용한다. 이를통해 로그인 상태를 유지할 수 있다.
HTTP 프로토콜은 상태가 없는데 stateless, 정보를 기억시켜주기 때문이다.
서버, 클라이언트 양쪽에서 쿠키 데이터를 사용하는 api 가 존재한다.
즉 req, res 둘다 모든 쿠키를 넘겨야 한다.
도메인 별로 데이터가 분리되지만, 같은 브라우저라면 값을 공유했다.
변화를 감지할 수 없다. (웹스토리지는 Storage event가 실행돼 변화를 감지하고 갱신해 반영한다.)
Secure 쿠키는 HTTPS 프로토콜 상에서 암호화된 요청일 경우에만 전송된다.
그러나 지워져도 되거나, 조작되거나 가로채이더라도 큰 지장이 없는 수준의 정보들만을 보관하도록 되어 있다.
중요한 정보를 저장할 때는 반드시 암호화를 적용하고, HttpOnly, Secure와 같은 속성을 사용하여 보안을 강화해야한다.
LifeTime
브라우저가 종료되면 자동으로 삭제된다. (sessionStorage가 쿠키의 이 점을 도입하였음)
- 세션 쿠키 (Expires, Max-Age 속성이 없는 쿠키) : 현재 세션이 끝날 때 삭제된다.
- 브라우저는 "현재 세션"이 끝나는 시점을 정의하여, 재시작할 때 세션을 복원해 세션 쿠키가 무기한 존재할 수 있도록 한다.
- 영속적인 쿠키 : Expires 속성에 명시된 날짜에 삭제되거나, Max-Age 속성에 명시된 기간 이후에 삭제된다.
Set-Cookie: id=[Cookie-Id]; Expires=Wed, 21 Oct 2024 07:28:00 GMT;
서버의 시간이 아니라 쿠키가 저장되는 클라이언트의 시간 기준
사용
- 서버쪽 사용이 필수적이고 잦다면, 웹스토리지가 아닌, 클라이언트와 서버와 인터렉션에 효과적인 쿠키를 사용하는 것이 좋다.
- 광고 7일동안 보지 않기 - 만료일, 지속시간 duration 기능(웹스토리지에 없음)
- 세션 관리
- 서버에 저장해야할 로그인, 장바구니, 게임스코어 등의 정보
- 트래킹 Tracking
- 사용자 행동 기록 및 분석
HttpOnly 플래그가 설정되지 않은 경우, 기본 쿠키들은 javascript로부터 읽을 수 잇다.
document.cookie = "dah_cookie=datdaradanadat"; //새로운 쿠키 생성
document.cookie = "apple_cookie=sweetapple";
console.log(document.cookie);
// logs "dah_cookie=datdaradanadat; pple_cookie=sweetapple"
단점
- 모은 요청마다 쿠키가 함게 전송되기 때문에 성능이 떨어지는 원인이 될수도 있음
- mobile data connecions 성능
Cookie 대신 LocalStorage
HTML5 이전에는 쿠키를 썻는데, 이후에 로컬스토리지로 많이 변경되었다.
- 모든 HTTP 요청에서 데이터를 주고받을 필요가 없다.
- 전체 트래픽, 낭비되는 대역폭의 양 줄일 수 있다.
- 대역폭 Bandwidth : 특정 시간 동안 네트워크를 통해 전송될 수 있는 최대 데이터의 양
- 데이터 전송이 빈번할 경우 많은 대역폭이 사용되는데, 불필요하게 사용되는 대역폭을 '낭비되는 대역폭'으로 간주한다.
- 문제점 : 서버 부하 증가, 느린 응답 시간, 사용자 데이터 사용량 증가
- 데이터가 유저의 로컬디스크에 저장되어있으면, 인터넷이 끊어져도, 데이터가 삭제되지 않기 때문이다.
쿠기의 용량은 4KB 이기 때문에, 많이 대체되었음.
WebStorage vs Cookie 차이점
WebStorage | Cookie | |
제한 | 용량제한 | 용량제한, 시간제한, 갯수제한 |
시간제한 설정 | 불가능 | 가능 |
데이터 형식 | 문자열, JS object | 문자열 |
데이터 전송 | 선택, 가공해서 전송가능 | 모든 쿠키 전송. 가공시 side effect 존재함 |
세션 정의? | 같은 오리진이라도, (sessionStorage) 다른탭이면 다른 세션이라고 정의 | 같은 오리진이면, 다른 탭/창 일지라도, 같은 세션이라고 정의 |
이벤트 | 변경 감지 event | 변경 감지 불가능 |
‼️ 키포인트
스토리지는 보안에 취약하기 때문에 중요한 정보를 저장하는 것은 안된다. 일단 데이터는 암호화 되는것이 좋다.
기본적으로 쿠키는 웹스토리지보다 보안에 취약하다. 통신과정에서 가로채기 쉬움
- HttpOnly, Secure 와 같은 속성을 사용해 보안을 강화할 수 있다.
- 당연히 중요한 정보는 암호화하여 보관한다.
웹스토리지의 객체 저장은 json.stringity 를 사용한다.
로그인 방식
- 쿠키 : 모든 http 통신에 로그인정보가 포함되어있어야 하기 때문에 쿠키에 사용자 정보를 담는것이 효율적이라는 의견
- 로컬스토리지 : Instance 하나로 묶어서 데이터를 통신할 수 있다. 그러나 사용자 정보가 영구적으로 보관되는건 위험하기도 하고, 보안 강화하는 플래그가 부족하다.
- 세션스토리지
- 하나의 도메인을 두개의 창을 열고, 하나의 창에서 로그인했을 경우
- 다른 창에도 로그인 상태가 되어야 한다.
- 세션스토리지는 다른 탭으로 구분되어, 로그인 상태가 공유되지 않는다.
- 로그인에서는 사용불가!
- 세션 기반 인증 시스템
- 세션 id 는 쿠키 헤더에 담아서 오기 때문에, 기본적으로 쿠키에서 관리하는것이 적절하다.
- 토큰 기반 인증 시스템
- accessToken : 암호화된 사용자 정보를 가지고 있기 때문에, 스토리지에 저장하는 것은 보안적으로 위험하다. 전역상태관리로 메모리에 저장하자!
- refreshToken : 사용자 정보를 직접 가지고 있지 않고, accessToken을 암호화를 풀 키 값이다. 이 토큰을 탈취된다고 한들, 사용자 정보가 탈취되는것은 아님! 그나마 중요도가 낮음.
- 서버와 통신시, refreshToken을 통해 사용자 인증하자!
- 쿠키의 `HttpOnly`, `Secure`, `SameSite`, `anti-CSRFtokens` 옵션으로 보안을 강화하자!
- 결론! accessToken은 메모리, refreshToekn은 쿠키에 저장하자!