[SeSACx코딩온] 쿠키(Cookie)
쿠키(Cookie)
0. 쿠키란?
쿠키는 클라이언트의 웹 브라우저에 저장되는 작은 데이터 조각입니다. 서버에서 클라이언트로 보내져 브라우저에 저장되며, 이후 클라이언트가 같은 서버에 다시 요청할 때마다 함께 전송됩니다. 이를 통해 서버는 클라이언트의 상태를 유지하고, 사용자에게 개인화된 경험을 제공할 수 있습니다.
1. 쿠키의 사용 목적
- 세션 관리
- 사용자가 로그인하면 서버는 사용자의 세션 ID를 쿠키에 저장합니다. 이후 사용자가 페이지를 이동하더라도 세션 ID를 통해 로그인 상태를 유지할 수 있습니다.
- (예시) 로그인 상태 유지, 장바구니 내용 저장 등
- 사용자 맞춤 설정
- 사용자가 선택한 테마나 언어 설정을 쿠키에 저장하여, 다음 번 방문 시에도 동일한 설정을 유지할 수 있습니다.
- (예시) 테마 설정, 언어 선택 등
- 추적 및 분석
- 쿠키를 사용하여 사용자의 방문 기록이나 행동을 추적하고, 이를 분석하여 웹사이트의 개선점을 찾거나 마케팅 전략을 세울 수 있습니다.
- (예시) 웹사이트 방문 기록, 사용자 행동 분석 등
2. 필요한 npm 패키지 설치
npm install express dotenv cross-env cookie-parser
express
: Node.js 웹 애플리케이션 프레임워크입니다.dotenv
: 환경 변수 파일을 로드하는 모듈입니다.cross-env
: 플랫폼에 상관없이 환경 변수를 설정할 수 있는 모듈입니다.cookie-parser
: 쿠키와 관련된 설정 및 처리하는 모듈입니다.
3. 환경 변수 설정
.env
파일
애플리케이션의 환경 변수를 정의하는 .env
파일을 사용하여 서버 포트와 쿠키 비밀 키를 설정합니다.
PORT=5000
COOKIE_SECRET=thiscookiesecretkeyhihello9876
COOKIE_SECRET
: 쿠키의 서명을 위한 비밀 키입니다. 이 값을 통해 쿠키가 변조되지 않았음을 검증할 수 있습니다.- 아무 문자열이나 넣어 유추하지 못하게 하는 것이 좋습니다.
4. 쿠키의 종류
1) 평문 쿠키
// 평문 쿠키 설정
app.use(cookieParser(process.env.COOKIE_SECRET));
const cookieConfig = {
httpOnly: true,
maxAge: 60 * 1000,
};
httpOnly
옵션을 사용하여 자바스크립트에서 접근하지 못하도록 하고,maxAge
를 통해 쿠키의 유효 기간을 설정합니다.- 평문 쿠키는 암호화되지 않은 일반 텍스트로 저장됩니다. 클라이언트가 이 쿠키를 수정하거나 위조할 수 있으며, 서버는 이를 검증할 방법이 없습니다.
- 평문 쿠키는 클라이언트에서 쉽게 수정될 수 있으며, 중요한 데이터를 저장하기에는 적합하지 않습니다. 평문 쿠키는 단순한 상태 정보를 저장하는 데 사용될 수 있지만, 보안이 중요한 정보는 서명된 쿠키를 사용하는 것이 좋습니다.
2) 서명된 쿠키
signed
옵션을true
로 설정하여 쿠키 값을 서명합니다.- 서명된 쿠키는 쿠키 값에 서명을 추가하여 무결성을 보장합니다. 서명된 쿠키는 클라이언트에서 수정할 수 없으며, 서버에서 서명을 검증하여 쿠키가 변조되지 않았음을 확인할 수 있습니다.
- 서버는 쿠키 값을 서명할 때 사용한 비밀 키와 클라이언트로부터 받은 서명을 비교하여 쿠키의 무결성을 검증합니다.
app.use(cookieParser(process.env.COOKIE_SECRET));
const cookieConfig = {
httpOnly: true,
maxAge: 60 * 1000,
signed: true // 서명된 쿠키
};
res.cookie('myKeyTest', 'myValueTest', cookieConfig); // (키, 값, 옵션)
(1) 서명된 쿠키의 주요 옵션
-
쿠키 이름 (key):
'myKeyTest'
- 쿠키의 이름을 지정합니다. 쿠키는 이름과 값의 쌍으로 저장됩니다. 클라이언트의 브라우저는 이 이름을 사용하여 쿠키를 식별하고 서버에 전송합니다.
-
쿠키 값 (value):
'myValueTest'
- 쿠키에 저장할 값을 지정합니다. 이 값은 클라이언트의 브라우저에 저장됩니다.
-
옵션 (options):
cookieConfig
- 쿠키의 동작 방식을 설정하는 다양한 옵션들을 포함합니다. 이 옵션들은 쿠키의 보안, 유효 기간, 접근 권한 등을 제어합니다.
(2) 서명된 쿠키의 주요 옵션
httpOnly
true
로 설정되면, 쿠키는 클라이언트 측 JavaScript에서 접근할 수 없습니다. 이는 XSS(교차 사이트 스크립팅) 공격으로부터 쿠키를 보호하는 데 도움이 됩니다.- (예시)
httpOnly: true
maxAge
- 쿠키의 유효 기간을 설정합니다. 쿠키가 생성된 시간부터 이 시간이 지나면 쿠키는 만료됩니다. 시간은 밀리초 단위로 설정합니다.
- (예시)
maxAge: 60 * 1000
(1분)
expires
- 쿠키의 만료 날짜와 시간을 설정합니다.
maxAge
와 비슷하지만,expires
는 절대적인 날짜와 시간을 지정합니다. - (예시)
expires: new Date(Date.now() + 60 * 1000)
- 쿠키의 만료 날짜와 시간을 설정합니다.
domain
- 쿠키가 유효한 도메인을 설정합니다. 이 도메인에서만 쿠키가 전송됩니다.
- (예시)
domain: 'example.com'
path
- 쿠키가 유효한 URL 경로를 설정합니다. 이 경로에 해당하는 URL에서만 쿠키가 전송됩니다.
- (예시)
path: '/'
secure
true
로 설정되면, 쿠키는 HTTPS 연결을 통해서만 전송됩니다. 이 옵션은 쿠키의 보안을 강화합니다.- (예시)
secure: true
sameSite
- 쿠키의 SameSite 속성을 설정하여 CSRF(사이트 간 요청 위조) 공격을 방지합니다.
Strict
,Lax
,None
중 하나로 설정할 수 있습니다. - (예시)
sameSite: 'Strict'
- 쿠키의 SameSite 속성을 설정하여 CSRF(사이트 간 요청 위조) 공격을 방지합니다.
signed
true
로 설정하면, 쿠키의 값에 서명을 추가하여 쿠키의 무결성을 검증합니다. 서명된 쿠키는 서버에서 서명을 확인하여 변조되지 않았음을 보장할 수 있습니다.- (예시)
signed: true
(3) 서명된 쿠키 예시
서명된 쿠키는 다음과 같은 형태로 서버와 클라이언트 간에 전달됩니다.
s%3AmyValueTest.hJ%2B5zrjA0i%2BCMvWo8bV5ldOFBkahM3DUIlM99CDAM88
s%3A
: 서명된 쿠키의 접두사로, 쿠키 값이 서명됨을 나타냅니다.myValueTest
: 실제 쿠키 값입니다.- 서명 문자열: 쿠키 값을 서명하기 위해 생성된 문자열입니다.
(4) 서명된 쿠키 검증 방식
- 서버가
"서명된 쿠키"
를 받으면,"s%3A"
를 보고 서명된 쿠키임을 인식합니다. - 서버의
비밀키(process.env.COOKIE_SECRET)
를 사용해 다시 서명하고 받은 서명이랑 비교합니다. - 두 값이 일치하면 쿠키가 변조되지 않았음을 신뢰하고 사용합니다.
5. cookie-parser
미들웨어
1) cookie.js
Express 애플리케이션에서 쿠키를 설정하고 처리하기 위해 cookie-parser
미들웨어를 사용합니다.
const express = require('express');
const cookieParser = require('cookie-parser'); // 쿠키 설정, 처리
const path = require('path');
const dotenv = require('dotenv');
const app = express();
app.set('view engine', 'ejs');
app.set('./views', './views');
// 환경변수를 로드
dotenv.config({
path: path.resolve(__dirname, '.env')
});
const port = process.env.PORT; // 참고: 환경변수보다 위에 위치하면 undefined 뜸.
// cookie-parser 미들웨어를 사용하여 쿠키를 해석
app.use(cookieParser(process.env.COOKIE_SECRET));
const cookieConfig = {
httpOnly: true, // 서버를 통해서만 쿠키에 접근 가능 -> 프론트 js에서 document.cookie로 접근 차단
maxAge: 60 * 1000, // 쿠키의 수명 (ms, 밀리초 단위)
signed: true, // // 쿠키 암호화 (req.signedCookies), 쿠키에 서명을 추가하여 변조를 방지
};
// 기본 페이지 렌더링
app.get('/', (req, res) => {
// 서버가 클라이언트한테 응답을 "함"
res.render('cookie');
});
// 서명된 쿠키 설정
app.get('/setCookie', (req, res) => {
// res.cookie(키, 값, 옵션);
// 쿠키를 설정하는 메서드
// 서버가 클라이언트한테 응답하는 게 아니라 "쿠키를 설정" (응답하기 전인 상태)
res.cookie('myKeyTest', 'myValueTest', cookieConfig);
res.send('Set signed cookie!');
});
// 쿠키 확인
app.get('/getCookie', (req, res) => {
// req.signedCookies
// cookie-parser가 만든 요청의 서명된 쿠키 해석
res.send(req.signedCookies);
});
// 쿠키 삭제
app.get('/clearCookie', (req, res) => {
// res.clearCookie(키, 값, 옵션)
// 쿠키를 삭제하는 메서드 (서버가 클라이언트에 응답하는 것이 아님)
// 쿠키를 생성할 때의 키, 값, 옵션이 일치해야 함 (단, maxAge/expires 키는 일치할 필요 없음)
res.clearCookie('myKeyTest', 'myValueTest', cookieConfig);
res.send('Deleted signed cookie!');
});
app.listen(port, () => {
console.log(`${port} 연결 성공`);
console.log('쿠키 비밀키 :', process.env.COOKIE_SECRET);
});
2) cookie-parser
사용법
(1) cookie-parser 미들웨어
- 요청에 실려온 쿠키를 해석해서 req.cookies 객체로 만듭니다.
(2) 미들웨어 설정
// 기본형태: cookieParser(secretKey, optionObj)
app.use(cookieParser(process.env.COOKIE_SECRET));
- secretKey: 비밀키
- 비밀키의 값을 통해 해당 쿠키가 이서버가 만든 쿠키임을 검증합니다.
- 쿠키는 클라이언트에 저장되는 정보이다보니 위조가 쉬워서 비밀키를 통해 만든 서명을 쿠키 뒤에 붙입니다.
- optionObj: 쿠키에 사용되는 옵션입니다.
(3) 서명된 쿠키 설정
-
res.cookie
메서드를 사용하여 서명된 쿠키를 설정합니다.signed
옵션을true
로 설정하면 쿠키에 서명이 추가되어 변조를 방지합니다.app.get('/setCookie', (req, res) => { res.cookie('myKeyTest', 'myValueTest', cookieConfig); // res.cookie res.send('Set signed cookie!'); });
(4) 쿠키 확인
-
req.signedCookies
를 사용하여 클라이언트로부터 받은 서명된 쿠키를 확인합니다.app.get('/getCookie', (req, res) => { res.send(req.signedCookies); // req.signedCookies });
(5) 쿠키 삭제
res.clearCookie
메서드를 사용하여 쿠키를 삭제합니다.-
쿠키를 삭제할 때는 쿠키를 설정할 때 사용한 키와 값, 옵션을 동일하게 지정해야 합니다.
app.get('/clearCookie', (req, res) => { res.clearCookie('myKeyTest', 'myValueTest', cookieConfig); // res.clearCookie res.send('Deleted signed cookie!'); });