브라우저Easy#98
localStorage, sessionStorage, Cookie의 차이점을 설명해주세요.
#브라우저#웹스토리지#Cookie#보안
힌트
저장 용량, 만료 시간, 서버 전송 여부를 기준으로 비교해보세요.
정답 및 해설
localStorage, sessionStorage, Cookie의 차이점을 설명해주세요.
웹 브라우저에서 클라이언트 측 데이터를 저장하는 방법으로 localStorage, sessionStorage, Cookie 세 가지가 있습니다. 모두 브라우저에 데이터를 저장하지만 저장 수명, 용량, 서버 전송 여부, 보안 옵션 등에서 중요한 차이가 있습니다. 사용 목적에 따라 적절한 저장소를 선택해야 합니다.
한눈에 비교
| 특성 | localStorage | sessionStorage | Cookie |
|---|---|---|---|
| 저장 수명 | 영구 (직접 삭제 전까지) | 탭/세션 종료 시 삭제 | 만료일 설정 가능 |
| 저장 용량 | 5~10MB | 5~10MB | 4KB |
| 서버 전송 | 자동 전송 안 됨 | 자동 전송 안 됨 | HTTP 요청마다 자동 전송 |
| 탭 간 공유 | 같은 출처 모든 탭 공유 | 같은 탭 내에서만 | 같은 출처 모든 탭 공유 |
| 접근 방법 | JavaScript | JavaScript | JavaScript, 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까지 저장 가능)
정리
| 항목 | localStorage | sessionStorage | Cookie |
|---|---|---|---|
| 수명 | 영구 (수동 삭제까지) | 탭 닫으면 삭제 | 설정 가능 (없으면 세션) |
| 용량 | 5~10MB | 5~10MB | 4KB |
| 서버 전송 | 없음 | 없음 | 매 요청마다 자동 전송 |
| 탭 간 공유 | 공유됨 | 탭마다 독립 | 공유됨 |
| JS 접근 | 가능 | 가능 | HttpOnly 시 불가 |
| 보안 옵션 | 없음 | 없음 | HttpOnly, Secure, SameSite |
| 주요 용도 | 사용자 설정, 장바구니 | 폼 임시 저장 | 인증 토큰, 세션 관리 |
핵심: 인증 토큰은 XSS 방지를 위해 HttpOnly Cookie에 저장하고, 사용자 환경설정은 localStorage에, 임시 폼 데이터는 sessionStorage에 저장하는 것이 권장 패턴입니다.