쿠키는 클라이언트 측에서 웹브라우저에 저장되는 데이터 입니다.
왜 클라이언트 측에 데이터를 저장하냐면 HTTP의 특징 중에 Connectionless와 Stateless 때문입니다. 매번 연결할때마다 다시 접속해서 인증을 받는 것은 비효율적입니다. State를 유지해주기 위해서 cookie를 사용합니다.
Connectionless
HTTP는 클라이언트가 요청(request)를 서버에 보내고, 서버는 클라이언트에게 응답(response)를 주고 연결을 끊습니다.
Stateless
connection을 끊는 순간 클라이언트와 서버의 통신이 끝나며 상태정보는 유지하지않는 특성입니다.
domain=site.com
path=/example
expires= Tue, 19 Jan 2022 03:14:07 GMT
max-age=3600
MaxAge
는 앞으로 몇초 동안 쿠키가 유효한지 설정하는 옵션입니다.Expires
는 언제까지 유효한지 Date를 지정합니다secure
secure
옵션이 설정된 경우, https://site.com에서 설정한 쿠키는 http://site.com에서 접근할 수 없습니다.자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정합니다. 명시되지않은 경우 false로 지정되어있습니다.
Cross-origin 요청을 받은 경우 요청에서 사용한 메소드와 해당 옵션의 조합으로 서버의 쿠키 전송 여부를 결정하게 됩니다.
samesite는 XSRF
를 막기 위해 만들어진 옵션입니다.
XSRF (cross-site request forgery)
현재 bank.com에 로그인되어있다고 가정할 때, 해당 사이트에서 사용되는 인증 쿠키가 브라우저에 저장되고, 브라우저는 bank.com에 요청을 보낼때마다 인증 쿠키를 함께 전송할 것입니다.
서버는 전송받은 쿠키를 이용해 사용자를 식별하고, 보안이 필요한 재정 거래를 처리합니다.
로그아웃하지않고 다른 창을 띄워서 웹 서핑을 하던 도중에 뜨하지않게 evil.com에 접속했을 때, 이 사이트의 해커에게 송금을 요청하는 폼이 있고, 이 폼이 자동으로 제출되도록 설정되어있을 때, 폼이 evil.com에서 은행사이트로 바로 전송될 때 인증 쿠키도 함께 전송이됩니다. bank.com에 요청을 보낼땜다 bank.com에서 설정한 쿠키가 전송되기 때문입니다.
samesite=lax
: Cross-origin 요청이면 'GET' 메소드에 대해서만 쿠키를 전송할 수 있습니다.samesite=strict
: Cross-origin이 아닌 same-site인 경우에만 쿠키를 전송할 수 있습니다.익스프레스에서 cookie-parser 모듈을 이용해 쿠키를 설정하거나 사용할 수 있습니다.
npm install cookie-parser
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser()); // cookieParser(secretKey, optionObj)
암호화된 쿠키를 사용하기 위해서는 cookieParser() 메소드의 인자로 임의의 문자열을 전달하면 됩니다.
res.cookie('쿠키이름', '쿠키 값', '옵션');
app.use(cookieParser('password'));
const cookieConfig = {
httpOnly: true,
maxAge: 100000,
signed: true
};
app.get('/set', (req, res) => {
res.cookie('key', 'value', cookieConfig);
res.send('set cookie');
});
app.get('/get', (req, res) => {
res.send(req.cookie);
})
세션은 쿠키를 기반으로 하고있지만, 사용자 정보 파일을 브라우저에 저장하지않고 세션은 서버 측에서 관리합니다.
req.session.save(function(err) {
})
req.session.destroy(function(err) {
})
req.session.reload(function(err) {
})
req.session.regenerate(function(err) {
})
req.session.touch()
cookie
SID 쿠키에 대한 설정입니다. cookie옵션을 객체 형식으로 줄 수 있고
default는 {path: '/', httpOnly: true, secure: false, maxAge: null}
입니다.
genid
SID로 사용할 로직을 정의하는 옵션입니다. genid: function(req) {}
형식으로 사용하면 되고, SID로 사용할 String을 return 하면 됩니다. default로 uid-safe라이브러리를 통한 SID 생성 함수를 사용합니다.
name
SID 쿠키의 이름을 설정합니다. default는 connect.sid
입니다.
proxy
리버스 프록시를 사용하는 경우 설정하는 옵션입니다. true
로 설정하면 X-Forwarded-Proto
헤더가 사용됩니다. default는 undefined
로, express에 trust proxy
로 등록된 주소에 대해서만 세션이 동작합니다.
resave
express-session은 기본적으로 세션에 변경이 있을 때만 세션을 저장합니다. resave:true
로 설정한다면 변경사항이 없어도 session을 다시 저장합니다. default는 true
입니다. false
로 설정하면 불필요한 session 저장을 막아주기 때문에 보통 false로 설정합니다.
saveUninitialized
세션이 생성되었지만 어떠한 데이터도 추가되거나 변경되지 않은 상태를 uninitialized라고 합니다.
saveUninitialized: ture
로 설정한다면 uninitiazlied session도 저장합니다.
false
로 설정하면 uninitiazlied session은 저장하지 않으므로 리소스 활용측면에서 조금 더 유리합니다.
rolling
세션이 만료되기 전, 새로고침 또는 페이지 이동이 일어나면 세션 만료를 갱신하느느 옵션입니다.
default는 rolling:false
입니다.
saveUninitiazlied 옵션이 false인 경우 uninintialized 세션에 대해서는 rolling이 작동하지않습니다. 따라서 단순히 로그인 여부 확인을 위해 session을 사용한다면 saveUninitialized 옵션을 true로 설정해줘야합니다.
secret
필수적으로 설정해줘야하는 옵션입니다. SID를 생성할 때 사용되는 비밀키로 String 또는 Array를 사용할 수 있습니다. Array를 사용하는 경우, 첫 번쨰 요소를 비밀키로 사용합니다.
store
세션을 어디에 저장할지 결정하는 옵션입니다. default는 MemoryStore로 메모리에 저장됩니다. 따라서 프로세스가 종료되면 세션이 없어집니다.
unset
삭제된 session을 어떻게 관리할지 결정하는 옵션입니다. destroy
와 keep
을 사용할 수 있는데, destroy
는 response가 끝날 때 store에서 삭제하는 옵션, keep
은 store에서 삭제하지는 않지만 더 이상 변경할 수 없게 하는 옵션입니다. default는 keep
입니다.
익스프레스에서 express-session 모듈로 세션을 지원합니다.
npm install express-session
const express = require('express');
const session = require('express-session');
const app = express();
app.use(session({
secret: 'password',
resave: false,
saveUninitialized: true
}));
secret : 보안을 위한 임의의 문자열(secret key)
resave : 세션 데이터가 바뀌기 전까지 세션 저장소의 값을 저장할지 여부(default: false)
saveUninitialized : 세션이 필요하기 전에 세션을 구동할지 여부(default: true)
store : 세션 저장소를 지정
예시
const express = require('express');
const session = require('express-session'); //express-session 모듈을 로드합니다.
const FileStore = require('session-file-store')(session); // 데이터베이스에 접속하는 것으로 정보를 객체로 저장해둡니다.
const app = express();
app.use(session({ // 사용자의 요청이 있을 때마다 해당 코드가 실행이 됩니다.
secret: 'password',
resave: false,
saveUninitialized: true,
store: new FileStore()
}));
app.get('/', function (req, res, next) {
if (req.session.num === undefined) {
req.session.num = 1;
}
else {
req.session.num = req.session.num+1;
}
res.send(`views: ${req.session.num}`)
})
session middleware
HTTP 통신을 할 때, 서버가 쿠키를 발행하고 클라이언트가 쿠키를 저장합니다. 그리고 나중에 재접속 할 때 서버는 클라이언트의 쿠키의 값을 확인합니다.
세션을 이용한다면 쿠키에 세션의 sid값을 저장해둡니다. 따라서 서버에는 sid 값을 가지고 서버내부에 저장되어있는 데이터베이스 혹은 파일과 비교하여 내용을 확인합니다.
const FileStore = require('session-file-store')(session);
express-session을 사용하면 request.session이라는 객체가 생성됩니다. 해당하는 객체에 property를 할당함으로 세션에 값을 줍니다.
쿠키는 클라이언트에 메모리 또는 파일에 저장하고, 세션은 서버 메모리에 저장됩니다.
쿠키는 클라이언트에 로컬에 저장되기도하고 특히 파일로 저장하는 경우 탈취, 변조될 위험이 있고, Request/Response에서 스나이핑 당할 위험이 있어 보안이 비교적 취약합니다. 반대로 session은 클라이언트 정보 자체는 서버에 저장되어 있으므로 비교적 안전합니다.
쿠키는 앞서 설명한 지속 쿠키의 경우에 브라우저를 종료하더라도 저장되어 있을 수 있는 반면에 세션은 서버에서 만료시간/날짜를 정해서 지워버릴 수 있기도 하고 세션 쿠키에 세션 아이디를 정한 경우, 브라우저 종료시 세션 아이디가 날아갈 수 있습니다.
세션을 주로 사용하면 되는데 왜 굳이 쿠키를 사용할까?
세션은 서버에 데이터를 저장 즉, 서버의 자원을 사용하기 때문에 서버 자원에 한계가 있고 메모리를 사용하다보면 속도 저하가 올 수 있기 때문입니다.
https://nesoy.github.io/articles/2017-03/Session-Cookie
https://interconnection.tistory.com/74
https://devuna.tistory.com/23
https://cotak.tistory.com/87
https://ko.javascript.info/cookie
https://lhwn.tistory.com/entry/1-Nodejs-express-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%9D%98-session