전체 목록
브라우저Easy#98

localStorage, sessionStorage, Cookie의 차이점을 설명해주세요.

#브라우저#웹스토리지#Cookie#보안
힌트

저장 용량, 만료 시간, 서버 전송 여부를 기준으로 비교해보세요.

정답 및 해설

localStorage, sessionStorage, Cookie의 차이점을 설명해주세요.

웹 브라우저에서 클라이언트 측 데이터를 저장하는 방법으로 localStorage, sessionStorage, Cookie 세 가지가 있습니다. 모두 브라우저에 데이터를 저장하지만 저장 수명, 용량, 서버 전송 여부, 보안 옵션 등에서 중요한 차이가 있습니다. 사용 목적에 따라 적절한 저장소를 선택해야 합니다.

한눈에 비교

특성localStoragesessionStorageCookie
저장 수명영구 (직접 삭제 전까지)탭/세션 종료 시 삭제만료일 설정 가능
저장 용량5~10MB5~10MB4KB
서버 전송자동 전송 안 됨자동 전송 안 됨HTTP 요청마다 자동 전송
탭 간 공유같은 출처 모든 탭 공유같은 탭 내에서만같은 출처 모든 탭 공유
접근 방법JavaScriptJavaScriptJavaScript, HTTP 헤더
보안 옵션없음없음HttpOnly, Secure, SameSite

localStorage

기본 사용법

// 데이터 저장 (문자열만 저장 가능)
localStorage.setItem('theme', 'dark');
localStorage.setItem('language', 'ko');

// 객체 저장 (JSON.stringify 필요)
const userSettings = { fontSize: 16, theme: 'dark', notifications: true };
localStorage.setItem('settings', JSON.stringify(userSettings));

// 데이터 읽기
const theme = localStorage.getItem('theme');  // 'dark'
const settings = JSON.parse(localStorage.getItem('settings'));

// 데이터 삭제
localStorage.removeItem('theme');

// 전체 삭제
localStorage.clear();

// 저장된 항목 수 확인
console.log(localStorage.length);

// 모든 키 순회
for (let i = 0; i < localStorage.length; i++) {
  const key = localStorage.key(i);
  console.log(key, localStorage.getItem(key));
}

특징 및 사용 사례

// 특징 1: 만료 없이 영구 저장
// 사용자가 직접 삭제하거나 코드로 삭제하기 전까지 유지

// 특징 2: 같은 출처(origin)의 모든 탭/윈도우에서 공유
// origin = protocol + hostname + port
// https://example.com 의 모든 탭은 localStorage 공유

// 특징 3: storage 이벤트 - 다른 탭에서 변경 시 감지 가능
window.addEventListener('storage', (event) => {
  console.log('다른 탭에서 변경:', event.key, event.newValue);
  if (event.key === 'theme') {
    applyTheme(event.newValue);  // 다른 탭의 테마 변경을 이 탭에도 반영
  }
});

// ✅ 적합한 사용 사례:
// - 사용자 설정 (테마, 언어, 폰트 크기)
// - 비로그인 사용자의 장바구니
// - 최근 본 항목
// - 게임 점수/진행 상황
// - 초안 자동 저장

주의사항

// ❌ 민감한 정보 저장 금지 (XSS 공격에 취약)
localStorage.setItem('accessToken', 'bearer-token...');  // 위험!
localStorage.setItem('password', '...');                  // 절대 금지!

// localStorage는 JavaScript로 직접 접근 가능
// XSS 공격 시 공격자가 모든 데이터를 읽을 수 있음
document.cookie;  // HttpOnly 쿠키는 접근 불가
localStorage.getItem('accessToken');  // 항상 접근 가능 → 위험

// 저장 공간 부족 시 예외 처리
try {
  localStorage.setItem('largeData', bigData);
} catch (e) {
  if (e.name === 'QuotaExceededError') {
    console.error('저장 공간이 부족합니다.');
    // 오래된 데이터 삭제 후 재시도
  }
}

sessionStorage

기본 사용법

// API는 localStorage와 동일
sessionStorage.setItem('currentStep', '2');
sessionStorage.setItem('formData', JSON.stringify({ name: 'Alice', email: '...' }));

const step = sessionStorage.getItem('currentStep');
sessionStorage.removeItem('currentStep');
sessionStorage.clear();

특징 및 사용 사례

// 특징 1: 탭/윈도우를 닫으면 자동 삭제
// 새로고침은 삭제 안 됨, 탭 닫기/브라우저 종료 시 삭제

// 특징 2: 같은 탭 안에서만 공유
// 같은 URL을 새 탭에서 열면 별개의 sessionStorage

// 예시: 두 탭에서 같은 사이트 접속
// 탭1.sessionStorage !== 탭2.sessionStorage  ← 완전히 독립적
// 탭1.localStorage === 탭2.localStorage      ← 공유됨

// ✅ 적합한 사용 사례:
// - 다단계 폼 임시 데이터 (결제, 회원가입 등)
// - 로그인 세션 중 임시 상태 (뒤로가기 방지)
// - 검색 필터 임시 저장 (탭 종료 시 초기화 원하는 경우)
// - 일회성 안내 팝업 표시 여부

// 다단계 폼 예시
function saveFormStep(stepData) {
  const allData = JSON.parse(sessionStorage.getItem('checkoutData') || '{}');
  Object.assign(allData, stepData);
  sessionStorage.setItem('checkoutData', JSON.stringify(allData));
}

// 탭이 닫히면 자동으로 폼 데이터 삭제 → 개인정보 보호

Cookie

기본 사용법

// JavaScript로 쿠키 설정
document.cookie = 'username=alice';
document.cookie = 'theme=dark; expires=Fri, 31 Dec 2024 23:59:59 GMT; path=/';
document.cookie = 'sessionId=abc123; max-age=3600; path=/; secure; samesite=lax';

// 쿠키 읽기 (모든 쿠키를 하나의 문자열로 반환)
console.log(document.cookie);  // "username=alice; theme=dark"

// HttpOnly 쿠키는 JavaScript로 접근 불가
// → 서버에서만 설정/읽기 가능

// 쿠키 삭제 (만료 날짜를 과거로 설정)
document.cookie = 'username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
// HTTP 응답 헤더로 서버에서 쿠키 설정
Set-Cookie: sessionId=xyz789; HttpOnly; Secure; SameSite=Strict; Max-Age=3600; Path=/
Set-Cookie: refreshToken=abc; HttpOnly; Secure; SameSite=Strict; Max-Age=604800; Path=/auth
Set-Cookie: preferences=dark-mode; SameSite=Lax; Max-Age=31536000; Path=/

쿠키 속성

Expires / Max-Age: 만료 시간 설정
  Expires=날짜     → 특정 날짜에 만료
  Max-Age=초       → 현재 시간 기준 초 단위 (우선순위 높음)
  둘 다 없으면     → 세션 쿠키 (브라우저 종료 시 삭제)

Path: 쿠키가 전송될 경로
  Path=/          → 모든 경로에서 전송 (기본값)
  Path=/api       → /api 이하 경로에서만 전송

Domain: 쿠키가 전송될 도메인
  Domain=example.com  → example.com과 서브도메인에서 전송
  생략              → 현재 도메인만 (서브도메인 제외)

Secure: HTTPS 연결에서만 전송
  → HTTP 연결에서는 쿠키 미전송

HttpOnly: JavaScript에서 접근 불가
  → document.cookie로 읽기/쓰기 불가
  → XSS 공격으로부터 쿠키 보호

SameSite: CSRF 공격 방지
  SameSite=Strict  → 같은 사이트 요청에만 전송
  SameSite=Lax     → 같은 사이트 + 외부 링크 클릭 시 전송 (기본값)
  SameSite=None    → 모든 크로스 사이트 요청에 전송 (Secure 필수)

쿠키 보안 속성 실무 활용

// 서버에서 인증 토큰 설정 (Node.js Express)
app.post('/auth/login', async (req, res) => {
  const { email, password } = req.body;
  const user = await authenticate(email, password);

  if (user) {
    const accessToken = generateAccessToken(user);
    const refreshToken = generateRefreshToken(user);

    // ✅ HttpOnly + Secure + SameSite로 토큰 보안 강화
    res.cookie('accessToken', accessToken, {
      httpOnly: true,      // XSS 방지
      secure: true,        // HTTPS만
      sameSite: 'strict',  // CSRF 방지
      maxAge: 15 * 60 * 1000,  // 15분
      path: '/'
    });

    res.cookie('refreshToken', refreshToken, {
      httpOnly: true,
      secure: true,
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60 * 1000,  // 7일
      path: '/auth/refresh'  // 갱신 엔드포인트에서만 전송
    });

    res.json({ success: true });
  }
});

쿠키 vs 토큰 인증

localStorage에 JWT 저장 방식:
❌ XSS로 토큰 탈취 가능
✅ CSRF 공격 없음
✅ 모바일 앱에서도 사용 가능

HttpOnly Cookie에 JWT 저장 방식:
✅ XSS로 접근 불가
✅ SameSite 속성으로 CSRF 방지
❌ 모바일 앱에서 관리 복잡
✅ 권장 방식 (보안상 더 안전)

Web Storage API의 한계와 대안

// localStorage/sessionStorage는 동기적 API → 대용량 처리 시 성능 문제
// 대안: IndexedDB - 비동기, 대용량 구조화 데이터 저장

// IndexedDB 예시
const request = indexedDB.open('myDatabase', 1);

request.onsuccess = (event) => {
  const db = event.target.result;
  const transaction = db.transaction(['users'], 'readwrite');
  const store = transaction.objectStore('users');
  store.add({ id: 1, name: 'Alice', email: 'alice@example.com' });
};

언제 무엇을 사용할까?

로그인 세션/인증 토큰:
→ HttpOnly Cookie 사용 (XSS, CSRF 방지)

사용자 환경설정 (테마, 언어):
→ localStorage 사용 (영구 저장, 서버 전송 불필요)

다단계 폼 임시 데이터:
→ sessionStorage 사용 (탭 종료 시 자동 삭제)

서버에서도 읽어야 하는 데이터:
→ Cookie 사용 (HTTP 요청마다 자동 전송)

대용량 데이터 (오프라인 캐시):
→ IndexedDB 사용 (수백 MB까지 저장 가능)

정리

항목localStoragesessionStorageCookie
수명영구 (수동 삭제까지)탭 닫으면 삭제설정 가능 (없으면 세션)
용량5~10MB5~10MB4KB
서버 전송없음없음매 요청마다 자동 전송
탭 간 공유공유됨탭마다 독립공유됨
JS 접근가능가능HttpOnly 시 불가
보안 옵션없음없음HttpOnly, Secure, SameSite
주요 용도사용자 설정, 장바구니폼 임시 저장인증 토큰, 세션 관리

핵심: 인증 토큰은 XSS 방지를 위해 HttpOnly Cookie에 저장하고, 사용자 환경설정은 localStorage에, 임시 폼 데이터는 sessionStorage에 저장하는 것이 권장 패턴입니다.