[인증 / 보안] 쿠키, 세션, 토큰 사용
클라이언트
Credentials
CORS 요청에 자격인증정보(credentials)를 포함하고 싶을 때 설정
- Credentials: 쿠키, Authorization인증 헤더, TLS client certificates
// client 헤더
withCredentials: true
// 모든 axios 요청에 withCredentials를 true로 설정
axios.defaults.withCredentials = true
// fetch 사용 시
fetch("localhost:4000", {
method: "POST",
credentials: "include"
})
서버
사용 모듈
const express = require('express'); // 서버
const cors = require('cors'); // CORS cross-orign 허용
const logger = require('morgan'); // 로그
const fs = require('fs'); // 파일에 접근
const https = require('https'); // https 사용
const app = express();
// Server 헤더
Access-Control-Allow-Credentials: true
response.setHeader("Access-Control-Allow-Credentials", "true")
// Express.js cors 사용 시
app.use(
cors({
origin: 'http://localhost:3000',
methods: ['GET', 'POST', 'OPTION'],
credentials: true,
})
);
쿠키
1. 모듈 불러오기(cookie-parser)
const cookieParser = require('cookie-parser');
2. 쿠키 저장(res.cookie)
res.cookie(키, 값, 옵션객체)
res.cookie('cookieId', id, cookiesOptions)
// 옵션객체 예시
const cookiesOptions = {
domain: 'localhost',
path: '/',
httpOnly: true,
sameSite: 'none',
secure: true,
}
3. 쿠키 접근(req.cookies 쿠키에 저장된 값 꺼내오기)
req.cookies
const cookieId = req.cookies.cookieId
const {cookieId} = req.cookies
4. 쿠키 삭제(res.clearCookie)
clearCookie의 두번째 인자인 옵션과 쿠키 저장 시 지정했던 옵션이 일치해야함
- 저장 기간을 정하는 maxAge, expires는 없어도 됨
res.clearCookie(키, 쿠키옵션)
res.clearCookie('cookieId', cookiesOptions)
=> 쿠키 사용은 req, 추가/삭제는 res로 접근
처음 인증시 res.cookie로 응답
이후 요청 헤더에 저장된 쿠키에 접근하여 유효성 검증 req.cookies
삭제 시 res.clearCookie
세션
쿠키로 세션을 전달함
1. 모듈 불러오기(express-session)
const session = require('express-session');
2. 세션 객체 기본값 설정(+쿠키옵션)
app.use(
session({
secret: '@codestates', // 비밀 키
resave: false,
saveUninitialized: true,
cookie: { // 쿠키 옵션. 'connect.sid'키로 저장됨
domain: 'localhost',
path: '/',
sameSite: 'none',
httpOnly: true,
secure: true,
},
})
);
3. 세션 객체에 값 추가(req.session)
req.session.키 = 값
req.session.sessionId = id // 세션 값 추가
req.session.cookie.maxAge = 1000 * 60 * 30 // 쿠키 옵션 추가
4. 세션 접근(req.session)
req.session.키
const sessionId = req.session.sessionId
5. 세션 삭제(req.session.destroy)
- 쿠키도 함께 삭제해주는 것이 좋음
req.session.destroy()
res.clearCookie('connect_sid', 쿠키옵션)
=> 세션은 사용/추가/삭제 모두 req로 접근
토큰
JsonWebToken(비동기)
1. 모듈 불러오기(jsonwebtoken)
const { sign, verify } = require('jsonwebtoken');
2. .env 환경 변수 설정
ACCESS_KEY : 인증을 위한 키
REFRESH_KEY : 갱신을 위한 키
ACCESS_SECRET=hello
REFRESH_SECRET=world
3. 토큰 생성(sign)
sign(payload, 비밀 키, 토큰옵션, 콜백함수)
// 상위 async
// 콜백함수: 에러 처리
const token = await sign(payload, process.env.ACCESS_SECRET, {
expiresIn: '1d', // 1일간 유효
})
4. 토큰 저장(LocalStorage, Session Storage, Cookie, 리액트 상태 등)
// 쿠키에 저장
res.cookie('access_jwt', token, cookiesOptions)
5. 토큰 검증(verify)
verify(토큰, 비밀 키, 콜백함수)
const token = req.cookies.access_jwt
const decoded = await verify(token, process.env.ACCESS_SECRET)
// payload 리턴
// 콜백함수 혹은 try/catch문으로 에러 처리
6. 토큰 삭제(토큰을 저장한 곳)
// 쿠키 삭제
res.clearCookie('access_jwt', cookiesOptions)
쿠키, 세션, 토큰 비교
설명 | 접속 상태 저장 | 단점 | |
쿠키 | http의 stateless를 보완해주는 도구 (데이터 전달 목적) |
클라이언트 | 접근이 쉽기 때문에 인증을 위해 사용하지 않음 |
세션 | 접속 상태와 권한 부여를 위해 세션 아이디를 쿠키로 전송 * 서버가 상태를 기억 |
서버 | 하나의 서버에서만 상태를 가지기 때문에 분산에 불리 |
토큰(jwt) | 토큰 자체로 무결성(integrity) 증명 가능 * 서버가 상태를 기억하지 않음 |
클라이언트(쿠키, localStorage, in-memory) |
모든 요청에 토큰을 보내야 함 |
세션은 서버가 상태를 저장하기 때문에
등록된 기기 강제 로그아웃 하기 가능,
(넷플릭스) 현재 로그인한 사용자, 시청중인 사용자를 알 수 있으나
사용자가 많아지면 세션DB가 커져야함(ex. Redis 사용)
토큰은 상태를 저장하지 않기 때문에 세션과 같은 기능을 하지 못하고
멤버십 등급 구분, 사용 권한 설정 등 정보 저장에 사용됨
-> 코로나 QR코드
토큰 검증이 빠르기 때문에 기본적으로 토큰으로 인증하고
서비스가 커지고, 유저 계정을 잘 관리하고 싶다면 세션으로 전환하는 경우가 많음
참고
2023.01.08