웹 스토리지 (LocalStorage vs SessionStorage), 쿠키, 세션, JWT

dyeon-dev·2023년 9월 6일
0
post-thumbnail

업로드중..

0) application 패널의 기능

현재 로딩된 웹페이지에서 리소스(이미지, 스크립트, 데이터 등)을 열람할 수 있는 패널이다.
웹 SQL DB, 로컬 및 세션 스토리지 쿠키, 어플리케이션 캐시, 이미지, 폰트, 스타일 시트를 포함한 모든 리소스를 검사한다.

브라우저에서 저장할 많은 저장소들과 캐시, 스토리지들이 많이 있다. 로그인과 관련해서 유저 정보에 대한 부분에도 많은 부분을 차지한다.

1) 로컬 스토리지, 세션 스토리지, 쿠키 차이점

세가지 모두 키-값 데이터 저장소이지만, 데이터 저장 기한에 따라 나뉜다.

  • 로컬 스토리지: 웹 페이지의 세션이 끝나더라도 데이터가 지워지지 않는다.(데이터의 영구성 보장)
    ex) 보안이 중요한 영구 데이터 (자동 로그인). 영구적으로 저장되어도 상관 없는 데이터들
  • 세션 스토리지: 웹 페이지의 세션이 끝날 때 저장된 데이터가 지워진다.
    ex) 보안이 중요한 임시 데이터 (은행 로그인,비로그인 장바구니). 민감한 데이터.
  • 쿠키: 클라이언트가 어떠한 웹 사이트를 방문할 경우, 그 사이트가 사용되고 있는 서버를 통해 클라이언트의 브라우저에 설치되는 작은 기록 파일을 일컫는다.
    쿠키는 웹사이트에 방문한 사용자 정보를 사용자의 하드 디스크에 저장, 클라이언트에서도 읽을 수 있지만 보통 서버 사이드에서 읽는 데이터
    ex) 빠른 처리가 필요한 임시 데이터(이벤트나 광고 팝업,서비스약관, 오늘 그만보기)

비밀번호 같은 중요정보는 스토리지에 저장하면 안된다. 로컬 스토리지나 세션 스토리지는 클라이언트 사이드이기 때문에 쉽게 해킹 당할 수 있다.

로컬 스토리지와 세션 스토리지는 웹 스토리지라고 부르는데 공통점은 두 기술 모두 데이터를 브라우저 상에 저장한다는 것이며, 자바스크립트 API가 완전히 동일한 형태이다.

같은 브라우저 상의 데이터를 다루는 것이기 때문에 당연히 이외의 다른 기기나 브라우저 간에 데이터 공유가 되고 영속되고 싶으면 클라우드 플랫폼이나 데이터베이스 서버를 사용해야 한다.

2) 기본 API

웹 스토리지는 키와 값으로 이루어진 데이터를 저장할 수 있다.

<세팅하는 법>

  • localStorage.setItem("key", value)
  • sessionStorage.setItem("key", "value")
  • setcookie("key","value","지속시간")
    새 항목을 생성하고 데이터 항목이 이미 존재하는 경우 기존 값을 업데이트 한다.

<스토리지 접근해서 값 가져오는 법>

  • localStorage.getItem("key")
  • sessionStorage.getItem("key")
  • document.cookie
// 키에 데이터 쓰기
localStorage.setItem("key", value);

// 키로부터 데이터 읽기
localStorage.getItem("key");

// 키의 데이터 삭재
localStorage.removeItem("key");

// 모든 키의 데이터 삭제
localStorage.clear();

// 저장된 키/값 쌍의 개수
localStorage.length;
> localStorage.getItem('name')
null
> localStorage.getItem('email')
null
> localStorage.setItem('email', 'test@user.com')
undefined
> localStorage.getItem('email')
"test@user.com"
> localStorage.setItem('email', 'test@admin.com')
undefined
> localStorage.getItem('email')
"test@admin.com"
> localStorage.removeItem('email')
undefined
> localStorage.getItem('email')
null

주의 사항 및 해결 방법

오직 string 타입만 지원한다. 웹 스토리지는 문자열 데이터 밖에 저장할 수 없기 때문에 다른 타입의 데이터를 저장하려고 할 때 문자형으로 변환한다.

> localStorage.setItem('obj', {a: 1, b: 2})
undefined
> localStorage.getItem('obj')
"[object Object]"

위와 같은 문제를 피하기 위해 JSON 형태로 데이터 변환하여 사용한다.

> localStorage.setItem('json', JSON.stringify({a: 1, b: 2}))
undefined
> JSON.parse(localStorage.getItem('json'))
{a: 1, b: 2}

로컬 스토리지에 쓸 데이터를 JSON 형태로 직렬화하고(stringify), 읽은 데이터를 JSON 형태로 역직렬화(parse)해주면 원본의 데이터를 그대로 얻을 수 있다.
임의로 지정한 데이터 유형을 저장하는 일반적인 방법은 없고 원본 개체의 변형에 영향을 미치지 않는다.

데이터 청소

로컬 스토리지에 저장된 데이터는 웹페이지를 닫을 때 사라지지 않으므로 직접 청소해주는 것이 좋다.

> localStorage.length
5
> localStorage.key(0)
"email"
> localStorage.removeItem('obj')
undefined
> localStorage.length
4
> localStorage.clear()
undefined
> localStorage.length
0

서버는 클라이언트의 로그인 요청에 대한 응답을 작성할 때, 클라이언트 측에 저장하고 싶은 정보를 응답헤더Set-Cookie에 담는다. 이후 해당 클라이언트는 요청을 보낼 때마다 매번 저장된 쿠키를 요청헤더의 Cookie에 담아 보낸다. 서버는 쿠키에 담긴 정보를 바탕으로 해당 요청의 클라이언트가 누군지 식별할 수 있다.

쿠키 단점

  • 보안 취약(요청 시 쿠키의 값을 그대로 보내, 유출 및 조작 당할 위험 존재)
  • 용량 제한
  • 웹 브라우저마다 쿠키에 대한 지원형태가 달라 브라우저 간 공유 불가능
  • 쿠키의 사이즈가 커질수록 네트워크에 부하가 심해진다.
  • 만료 기한이 있는 키-값 저장소, 프론트 백엔드 통신과 관련이 있기에 용량이 적다.

4) 세션 (Session)

세션은 비밀번호 등 클라이언트의 인증 정보를 쿠키가 아닌 서버 측에 저장하고 관리한다.
서버는 클라이언트의 로그인 요청에 대한 응답을 작성할 때, 인증 정보는 서버에 저장하고 클라이언트 식별자인 JSESSIONID를 쿠키에 담는다. 이후 클라이언트는 요청을 보낼때마다 JSESSIONID 쿠키를 함께 보낸다. 그러면 서버는 JSESSIONID의 유효성을 판별해 클라이언트를 식별한다.

세션 기반 인증의 장점

  • 서버가 클라이언트의 웹 브라우저에 의존하지 않아도 된다.
  • 쿠키를 포함한 요청이 외부에 노출되어도 세션 ID 자체는 유의미한 개인 정보를 담지 않는다.
  • 각 사용자마다 고유한 세션 ID가 발급되기 때문에, 요청이 들어올 때마다 회원 정보를 확인(로그인)할 필요 없다.

5) 토큰 기반 인증 JWT (인증 상위버전이랄까)

Json Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰이다.
JSON 객체를 사용하여 정보를 안전하게 전달해준다. JWT는 인증여부 확인을 위한 값, 유효성 검증을 위한 값 그리고 인증 정보 자체를 담고 있기 때문에 인증서버에 묻지 않고도 사용 가능하다.
백엔드에서 jwt를 생성할 때 해당 user가 누구인지 식별할만한 정보를 담을 수 있다.
매번 로그인을 하지 않도록 access token을 주고받아서 사용자 인증을 진행한다.

사용목적
1. 회원인증: JWT를 이용해서 회원정보를 주고받게 되면 유저의 정보를 세션에 유지할 필요가 없게 된다.
2. 정보교류: 데이터를 주고받을 때 안정성있게 정보 교환을 할 수 있다.

JWT 기반 인증은 쿠키/세션 방식과 유사하게 JWT 토큰(access token)HTTP 헤더에 실어 서버가 클라를 식별한다.

JWT의 구조는 Header, Payload, Signature 세가지 문자열의 조합으로 이루어져있다.

Header는 alg와 typ을 갖고 있다.
alg는 정보를 암호화할 해싱 알고리즘, typ는 토큰의 타입을 지정한다.

{
	"alg": "HS256",
	"typ": "JWT"
}

Payload

Payload는 실제로 토큰에 담을 정보를 담고있다.
주로 클라이언트 고유 ID, 유효기간 등이 포함된다.
key-value 형식으로 이루어진 한 쌍의 정보를 Claim이라고 한다.

{
	"sub": "1234567890",
	"name": "John Doe",
	"iat": 1516230922
}

Signature

Signature는 인코딩된 Header와 Payload를 더한 뒤, 비밀키로 해싱하여 생성한다.
Header와 Payload는 단순 인코딩된 값이라 해커가 복호화하고 조작할 수 있지만, Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상 복호화할 수 없다.

따라서 Signature는 토큰의 위변조 여부를 확인하는 데 사용된다.

HMACSHA256(
	base64UrlEncode(header) + "." +
	base64UrlEncode(payload),
	secret_key
)

JWT 토큰 저장 방법
access token을 만들어 local storage에 저장하기
-> 한번 로그인하면 더이상 안해도 되도록 Local Storage에 저장 (해당 도메인에 영구 저장)
-> setItem 메소드 사용해서 키 값 저장
localStorage.setItem("access_token", res["Authorization"]);

JWT 인증과정
1. 클라이언트 로그인 요청이 들어오면, 서버는 검증 후 고유 ID 등의 정보를 Payload에 담는다.
2. 서버는 암호화할 비밀키를 사용해 access token(JWT)을 발급한다.
3. 클라이언트는 전달받은 JWT를 저장해두고, 서버에서 요청할 때마다 토큰을 요청 헤더 Authorization에 포함시켜 함께 전달한다.
4. 서버는 JWT의 Signature을 비밀키로 복호화한 다음, 위변조 여부 및 유효기간(signature) 등을 확인한다.
5. 유효한 토큰이라면 요청에 응답한다.

토큰 장점

  • Header와 Payload를 가지고 Signature를 생성하므로 데이터 위변조를 막을 수 있다.
  • 인증 정보에 대한 별도의 저장소가 필요 없다. (I/O 처리 필요 없음)
  • JWT는 토큰에 대한 기본 정보와 전달할 정보 및 토큰이 검증됐음을 증명하는 서명 등 필요한 모든 정보를 자체적으로 지니고 있다.
  • 클라이언트의 인증 정보를 저장하는 세션과 다르게, 서버는 무상태(Stateless)가 된다.
  • 토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능하다. (토큰 서버 활용)
  • OAuth의 경우 Facebook, Google 등 소셜 계정을 이용해 다른 웹서비스에서도 로그인 할 수 있다.

토큰 단점

  • Patload 자체는 암호화되지 않기 때문에 유저의 정보는 중요한 정보는 담을 수 없다. (pw 등)
  • 토큰을 탈취당하면 대처하기 어렵다. 토큰은 한 번 발급되면 유효기간이 만료될 때까지 계속 사용이 가능하다.
  • 특정 사용자의 접속을 강제로 만료하기 어렵다. (쿠키/세션 기반 인증은 서버 단에서 쉽게 삭제할 수 있지만 토큰은 그게 안 됨)

참고:

0개의 댓글