next.js

[Next & Node] 프론트와 백엔드간의 쿠키 공유하기 (Cookie)

JJIMJJIM 2024. 6. 27. 03:52
728x90
반응형
SMALL

[Next & Node] 프론트와 백엔드간의 쿠키 공유하기 (Cookie)

https://y-chyachya.tistory.com/111 이 글에서 노드와 axios간의 쿠키 공유하는 법을 설명한적이 있습니다.

그런데 이번에 토이플젝을 하면서 쿠키때문에 고생한 경험을 좀 더 자세히 기록해보려고 합니다.

넥스트와 노드를 가지고 각각 프론트, 백엔드를 작업했습니다.

 

 

 

증상

백엔드에서 cors/쿠키공유 이슈를 해결하기 위해 cors 미들웨어를 사용 + express-session 미들웨어를 이용해서 쿠키를 공유할 수 있게 하기위해서 사용했습니다.

클라이언트에서는 fetch 함수를 기준으로 호출할 때 credentials: include 옵션을 추가했습니다.

그런데도 아무리해도 쿠키가 공유가 안되서 결국엔 클라이언트에서 api router 실행 넥스트의 서버함수에서 쿠키를 직접 삽입해서 보내주기까지 했었습니다. 마지막의 이 방법으로 결국 성공은 했는데...

이후에 왜 그동안 쿠키 공유가 안됐는지 알고 보니 쿠키를 심을 때 (예: 로그인 후 프론트 서버에서 로그인 세션을 쿠키에 connect.id값으로 저장) 에도 쿠키를 공유할 수 있는 옵션을 넣어서 저장했어야 하는것 이었습니다.

그냥 기본 쿠키 저장만 하고 아예 기억에서 없다가 이번에 찾았는데 이렇게 허무할 수가 없었습니다. 

 

[프론트 /src/auth.ts]

import { cookies } from 'next/headers';
import cookie from 'cookie';

let setCookie = authResponse.headers.get('Set-Cookie');
const parsed = cookie.parse(setCookie);

const cookieOptions = {
  ...parsed,
  httpOnly: true,
  secure: process.env.NEXT_PUBLIC_MODE === 'production',
} as any;

if (process.env.NEXT_PUBLIC_MODE === 'production') {
  cookieOptions.domain = '.쿠키 공유가 필요한 도메인'; // '.' 붙이는게 중요!
}

cookies().set('connect.sid', parsed['connect.sid'], cookieOptions);

 

위와같이 쿠키를  브라우저에 심을때도 차후에 공유를 생각해서 심어야 함을 이번에 크게 배웠습니다.

프론트에서는 쿠키를 심을 때 위와같이 해주고, 사용할때에는 fetch 옵션에 credentials: 'include'를 적용해줘야 합니다.

 

[fetch 함수 호출 예시]

fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/post`, {
    method: 'post',
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(json 데이터),
  })

 

그리고 백엔드에서는 cors, express-session 미들웨어를 이용해서 cors와 쿠키공유를 위한 옵션을 추가해줘야 합니다.

 

[백엔드 app.js]

app.use(
  cors({
  	// true or * // access-control-allow-origin가 true된다. --> 다른 도메인끼리 api 요청
    origin: [필요한 도메인 배열],
    // access-control-allow-credential가 true된다. --> 다른 도메인끼리 쿠키 전달
    credentials: true,
  })
);

app.use(session({
  saveUninitialized: false,
  resave: false,
  secret: process.env.COOKIE_SECRET,
  proxy: process.env.NODE_ENV === 'production',
  cookie: {
    httpOnly: true,
    // 프로덕션 환경에서만 secure 적용
    secure: process.env.NODE_ENV === 'production',
    // 크로스 도메인 설정
    sameSite: process.env.NODE_ENV === 'production' ? 'None' : 'Lax',
    // 프로덕션 도메인 설정
    domain: process.env.NODE_ENV === 'production' ? '.도메인' : undefined,
  }
}));

 

 

 

옵션들

옵션들을 간단히 설명해보자면

 

1. httpOnly

  • 설명: httpOnly 속성을 설정하면 자바스크립트에서 쿠키에 접근할 수 없게 됩니다. 이는 XSS(교차 사이트 스크립팅) 공격으로부터 쿠키를 보호하는 데 도움이 됩니다.
  • 예시: httpOnly: true

 

2. saveUninitialized

  • 설명: 세션이 수정되지 않았어도 세션을 저장할지 여부를 결정합니다. 이 옵션을 false로 설정하면, 세션이 초기화되지 않은 상태에서는 저장되지 않습니다.
  • 예시: saveUninitialized: false

 

3. resave

  • 설명: 세션이 수정되지 않았어도 세션을 강제로 다시 저장할지 여부를 설정합니다. false로 설정하면, 세션이 변경되지 않았을 때는 저장하지 않습니다.
  • 예시: resave: false

 

4. proxy

  • 설명: 애플리케이션이 프록시 서버 뒤에 있을 때, 신뢰할 수 있는 프록시를 통해 요청이 오는지를 설정합니다. 이를 통해 secure 설정이 프록시 서버에 의해 올바르게 처리되도록 할 수 있습니다.
  • 이 옵션은 내가 하고있는 토이 프로젝트를 nginx를 통해서 https를 적용했기 때문에 추가한 옵션입니다.
  • 예시: proxy: true

 

5. secret

  • 설명: 쿠키의 서명에 사용되는 비밀 키입니다. 이 비밀 키를 사용하여 세션 쿠키를 암호화하고 검증합니다.
  • 예시: secret: 'your-secret-key'

 

6. secure

  • 설명: secure 속성을 설정하면 HTTPS(SSL/TLS)를 사용하는 연결에서만 쿠키가 전송됩니다. 이를 통해 네트워크 상에서 쿠키가 도난당하지 않도록 보호합니다.
  • 예시: secure: true

 

7. sameSite

  • 설명: sameSite 속성을 설정하여 크로스 사이트 요청에서 쿠키가 전송되는 방식을 제어할 수 있습니다. 이는 CSRF(교차 사이트 요청 위조) 공격을 방지하는 데 도움이 됩니다.
    • Strict: 동일한 사이트에서만 쿠키가 전송됩니다.
    • Lax: 기본적으로 동일한 사이트에서만 전송되지만, 일부 경우(예: 사용자가 링크를 클릭할 때)에는 크로스 사이트 전송을 허용합니다.
    • None: 모든 크로스 사이트 요청에 대해 쿠키가 전송됩니다.
  • 예시: sameSite: 'Strict'

 

8. domain

  • 설명: 쿠키가 유효한 도메인을 설정합니다. 지정된 도메인 및 하위 도메인에서만 쿠키가 전송됩니다.
  • 예시: domain: 'example.com'

 

 

 

 

로컬에서 쿠키 공유하기

  • 프론트서버에서 쿠키를 브라우저에 삽입할 때
    • httpOnly: true
    • secure: false
  • 백엔드 옵션
    • credentials: true,
    • httpOnly: true,
    • secrue: false
  • 클라이언트에서 fetch함수 실행할 때
    • credentials: 'incldue'

 

운영에서 쿠키 공유하기

  • 프론트서버에서 쿠키를 브라우저에 삽입할 때
    • httpOnly: true
    • secure: true
    • domain: '. + 필요한 도메인'
  • 백엔드 옵션
    • credentials: true,
    • httpOnly: true,
    • secrue: true
    • domain: 필요 도메인
  • 클라이언트에서 fetch함수 실행할 때
    • credentials: 'incldue'

 

서버 액션 (서버함수)에서 쿠키 공유하기

  • 위 내용 + 서버함수에서 fetch를 실행할때에는 쿠키를 강제로 집어넣어줘야합니다.
    • credentials: 'include'
    • headers: {Cookie: cookies().toString()}
  • 중요한건 cookies는 서버 컴포넌트에서만 사용할 수 있는 함수이기 때문에 서버함수가 서버컴포넌트에서만 쓰일 수 있도록 해야합니다.

 

 

 

 

 

 

 

 

 

 

 

참조

https://www.inflearn.com/course/%EB%85%B8%EB%93%9C%EB%B2%84%EB%93%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A6%AC%EB%89%B4%EC%96%BC/dashboard

 

[리뉴얼] React로 NodeBird SNS 만들기 강의 | 조현영 - 인프런

조현영 | 리액트 & 넥스트 & 리덕스 & 리덕스사가 & 익스프레스 스택으로 트위터와 유사한 SNS 서비스를 만들어봅니다. 끝으로 검색엔진 최적화 후 AWS에 배포합니다., 새로 만나는 제로초의 리액트

www.inflearn.com

 

 

 

728x90
반응형
LIST