코드스테이츠(SEB_FE_42)

[인증 / 보안] 쿠키, 세션, 토큰 사용

codeyun2 2023. 1. 8. 16:00

클라이언트

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코드

 

토큰 검증이 빠르기 때문에 기본적으로 토큰으로 인증하고

서비스가 커지고, 유저 계정을 잘 관리하고 싶다면 세션으로 전환하는 경우가 많음

 

 

 

 

참고

credential 설정

 

2023.01.08