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

    728x90
    반응형

    [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
    반응형

    댓글