쿠키
브라우저가 서버로부터 응답으로 Set-Cookie 헤더를 받은 경우 해당 데이터를 저장한 뒤 모든 요청에 포함하여 보낸다.
- 쿠키는 사용자가 naver.com과 같은 웹사이트를 방문할 때마다 이전에 방문했던 정보를 기억하는 데이터 파일이다
- 데이터를 여러 사이트에 공유할 수 있기 때문에 보안에 취약할 수 있다.
- 쿠키는
userId=user-1321;userName=sparta
와 같이 문자열 형식으로 존재하며 쿠키 간엔느 세미콜론으로 구분된다.
세션
쿠키를 기반으로 구성된 기술이다. 클라이언트가 마음대로 데이터를 확인할 수 있던 쿠키와는 다르게 세션은 데이터를 서버에만 저장한다.
- 세션은 일반적으로 세션 id를 쿠키를 이용해 클라이언트에게 전달하여, 서버는 이 세션 id를 사용해 저장된 세션 데이터를 조회합니다.
- 세션을 통해 사용자의 상태정보를 서버에 저장하면, 서버는 사용자의 상태를 추적할 수 있다.
- 보안성은 좋으나, 반대로 사용자가 많은 경우 서버에 저장해야 할 데이터가 많아져 서버 컴퓨터가 감당하지 못하는 문제가 생긴다.
- 쿠키와 마찬가지로 만료 기간이 있다.
서버가 클라이언트의 요청을 수신할 때 서버는 응답과 함께
Set-Cookie
라는 헤더를 함께 전송할 수 있다. 그 후 쿠키는 서버에 의해 만들어진 응답과 함께 Cookie HTTP 헤더 안에 포함되어 전달 받는다.
// 'Set-Cookie'를 이용하여 쿠키를 할당하는 API
app.get("/set-cookie", (req, res) => {
let expire = new Date();
expire.setMinutes(expire.getMinutes() + 60); // 만료 시간을 60분으로 설정합니다.
res.writeHead(200, {
'Set-Cookie': `name=sparta; Expires=${expire.toGMTString()}; HttpOnly; Path=/`,
});
return res.end();
});
// 'res.cookie()'를 이용하여 쿠키를 할당하는 API
app.get("/set-cookie", (req, res) => {
let expires = new Date();
expires.setMinutes(expires.getMinutes() + 60); // 만료 시간을 60분으로 설정합니다.
res.cookie('name', 'sparta', {
expires: expires
});
return res.end();
});
일반적으로 쿠키는 req.headers.cookie
에 들어있다. req.headers
는 클라이언트가 요청한 Request의 헤더를 의미합니다.
// 'req.headers.cookie'를 이용하여 클라이언트의 모든 쿠키를 조회하는 API
app.get('/get-cookie', (req, res) => {
const cookie = req.headers.cookie;
console.log(cookie); // name=sparta
return res.status(200).json({ cookie });
});
쿠키를
req.cookies
객체로 만들어준다.req.headers.cookie
와 같이 번거로게 사용하지 않아도 된다.
# yarn을 이용해 cookie-parser를 설치합니다.
yarn add cookie-parser
app.use(cookieParser());
import cookieParser from 'cookie-parser';
app.use(cookieParser());
// 'req.cookies'를 이용하여 클라이언트의 모든 쿠키를 조회하는 API
app.get('/get-cookie', (req, res) => {
const cookies = req.cookies;
console.log(cookies);
return res.status(200).json({ cookie: cookies });
});
쿠키의 형태가 name=sparta
에서 { name: 'sparta' }
형태의 객체로 변환되었다.
쿠키에는 사용자가 누구인지 확실하게 구분할 수 있는 정보를 넣어야 한다. 그래야 민감한 정보는 서버에서만 관리하고, 사용자 식별 정보를 통해 사용자의 정보를 반환할 수 있게 된다.
/set-session
을 호출했을 때 name=sparta
의 정보를 서버에 저장하고, 저장한 시간 정보를 쿠키로 반환 받는 API,
get-session
API를 호출했을 때 쿠키의 시간 정보를 이용하여 서버에 저장된 name
정보를 출력하는 API를 만들 수 있다.
let session = {};
app.get('/set-session', function (req, res, next) {
// 현재는 sparta라는 이름으로 저장하지만, 나중에는 복잡한 사용자의 정보로 변경될 수 있습니다.
const name = 'sparta';
const uniqueInt = Date.now();
// 세션에 사용자의 시간 정보 저장
session[uniqueInt] = { name };
res.cookie('sessionKey', uniqueInt);
return res.status(200).end();
});
session
객체를 생성set-session
API가 호출되면 name=sparta
의 정보를 세션에 삽입하고, 해당하는 데이터를 검색하기 위한 시간 정보를 쿠키로 반환app.get('/get-session', function (req, res, next) {
const { sessionKey } = req.cookies;
// 클라이언트의 쿠키에 저장된 세션키로 서버의 세션 정보를 조회합니다.
const name = session[sessionKey];
return res.status(200).json({ name });
});
sessionKey
를 이용하여 session
에 저장된 데이터를 불러온다.요구사항
1. cookie-parser 미들웨어를 적용해주세요!
2.GET
Method로http://localhost:5001/set
을 호출했을 때, name이라는 이름을 가진 “nodejs” 문자열을 저장한 쿠키를 반환해주세요.
3.GET
Method로http://localhost:5001/get
을 호출했을 때, 클라이언트에게 전달받은 모든 쿠키 정보들이 반환되는 API를 만들어주세요!
import express from 'express';
import cookieParser from 'cookie-parser';
const app = express();
const PORT = 5001;
app.use(express.json());
app.use(cookieParser());
app.get("/set", (req, res) => {
res.cookie('name', 'nodejs');
return res.status(200).end();
});
app.get("/get", (req, res) => {
const cookies = req.cookies;
return res.status(200).json({ cookie: cookies });
});
app.listen(PORT, () => {
console.log(PORT, '포트로 서버가 열렸어요!');
});
JWT(Json Web Token)은 웹 표준으로써, 서버와 클라이언트 사이에서 정보를 안전하게 전송하기 위해 도움을 주는 웹 토큰(Web Token)
JWT는 크게 세 부분 헤더, 페이로드, 서명으로 구성되어있다. 각각의 부분은 점(.)으로 분리된다.
{
"alg": "HS256",
"typ": "JWT"
}
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
각 부분을 Base64로 인코딩하여, 점(.)으로 연결하면 최종적으로 JWT를 생성하게 된다.
이렇게 생성된 JWT는 쿠키 또는 Path Parameter를 통해 전달될 수 있다.
JWT는 비밀 키를 모르더라도 복호화가 가능하다
민감한 정보는 담지 않도록 한다.
JavaScript와 같이 특정 언어에서만 사용 가능한 것은 아니다.
데이터를 교환하고 관리하는 방식인 쿠키/세션과 달리, JWT는 단순히 데이터를 표현하는 형식이다.
# yarn을 이용해 프로젝트를 초기화합니다.
yarn init -y
# jsonwebtoken, express 라이브러리를 설치합니다.
yarn add jsonwebtoken express
josnwebtoken
라이브러리의 sign
메서드를 사용해 JWT를 생성import jwt from 'jsonwebtoken';
const token = jwt.sign({ myPayloadData: 1234 }, 'mysecretkey');
console.log(token); // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJteVBheWxvYWREYXRhIjoxMjM0LCJpYXQiOjE2OTA4NzM4ODV9.YUmYY9aef9HOO8f2d6Umh2gtWRXJjDkzjm5FPhsQEA0
sign
메서드는 첫 번째 인자로 Payload 데이터를, 두 번째 인자로 비밀 키를 받아 JWT를 생성한다.josnwebtoken
라이브러리의 decode
메서드를 사용해 JWT를 복호화import jwt from 'jsonwebtoken';
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJteVBheWxvYWREYXRhIjoxMjM0LCJpYXQiOjE2OTA4NzM4ODV9.YUmYY9aef9HOO8f2d6Umh2gtWRXJjDkzjm5FPhsQEA0";
const decodedValue = jwt.decode(token);
console.log(decodedValue); // { myPayloadData: 1234, iat: 1690873885 }
josnwebtoken
라이브러리의 verify
메서드를 사용해 JWT를 검증import jwt from 'jsonwebtoken';
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJteVBheWxvYWREYXRhIjoxMjM0LCJpYXQiOjE2OTA4NzM4ODV9.YUmYY9aef9HOO8f2d6Umh2gtWRXJjDkzjm5FPhsQEA0";
const decodedValueByVerify = jwt.verify(token, "mysecretkey");
console.log(decodedValueByVerify); // { myPayloadData: 1234, iat: 1690873885 }
import jwt from 'jsonwebtoken';
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJteVBheWxvYWREYXRhIjoxMjM0LCJpYXQiOjE2OTA4NzM4ODV9.YUmYY9aef9HOO8f2d6Umh2gtWRXJjDkzjm5FPhsQEA0";
const decodedValueByVerify = jwt.verify(token, "secretkey");
console.log(decodedValueByVerify);
// JsonWebTokenError: invalid signature
잘못된 비밀 키를 이용하여 검증하면 에러가 발생한다.
import express from 'express';
const app = express();
app.post('/login', function (req, res, next) {
const user = { // 사용자 정보
userId: 203, // 사용자의 고유 아이디 (Primary key)
email: "archepro84@gmail.com", // 사용자의 이메일
name: "이용우", // 사용자의 이름
}
res.cookie('sparta', user); // sparta 라는 이름을 가진 쿠키에 user 객체를 할당합니다.
return res.status(200).end();
});
app.listen(5002, () => {
console.log(5002, "번호로 서버가 켜졌어요!");
});
sparta
이름을 가진 쿠키에 할당된다.import express from 'express';
import JWT from 'jsonwebtoken';
const app = express();
app.post('/login', (req, res) => {
// 사용자 정보
const user = {
userId: 203,
email: 'archepro84@gmail.com',
name: '이용우',
};
// 사용자 정보를 JWT로 생성
const userJWT = JWT.sign(
user, // user 변수의 데이터를 payload에 할당
'secretOrPrivateKey', // JWT의 비밀키를 secretOrPrivateKey라는 문자열로 할당
{ expiresIn: '1h' }, // JWT의 인증 만료시간을 1시간으로 설정
);
// userJWT 변수를 sparta 라는 이름을 가진 쿠키에 Bearer 토큰 형식으로 할당
res.cookie('sparta', `Bearer ${userJWT}`);
return res.status(200).end();
});
app.listen(5002, () => {
console.log(5002, '번호로 서버가 켜졌어요!');
});
sparta
이름을 가진 쿠키에 할당한다.