[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는 서버 컴포넌트에서만 사용할 수 있는 함수이기 때문에 서버함수가 서버컴포넌트에서만 쓰일 수 있도록 해야합니다.
참조
[리뉴얼] React로 NodeBird SNS 만들기 강의 | 조현영 - 인프런
조현영 | 리액트 & 넥스트 & 리덕스 & 리덕스사가 & 익스프레스 스택으로 트위터와 유사한 SNS 서비스를 만들어봅니다. 끝으로 검색엔진 최적화 후 AWS에 배포합니다., 새로 만나는 제로초의 리액트
www.inflearn.com
'next.js' 카테고리의 다른 글
[Next & Node] Socket.io로 채팅 구현하기 (0) | 2024.07.05 |
---|---|
[Next] 유저정보 수정 후 바로 서버 세션 업데이트하기 (update server session) (0) | 2024.06.18 |
[Next] <Image>으로 레이아웃 시프트 예방 (feat. plaiceholder, skeloton) (0) | 2024.05.26 |
[Next] UseSelectedLayoutSegment / UsePathname Hook (0) | 2024.05.13 |
[Next] App Router의 폴더들 (0) | 2024.05.13 |
댓글