코드스테이츠/코드스테이츠 @ 개발 일지

[코드 스테이츠] 94일차, "인증 / 보안 - Cookie, Session"

Je-chan 2021. 10. 20. 23:40

 

  오늘은 쿠키와 세션에 대한 공부를 진행했다. 배운 개념들이 많이 있었지만 그 개념들은 매번 주말 개발 복습할 때 하기로 했고, 스프린트를 진행하면서 생겼던 이슈들과 내가 작성한 코드들을 생각해보는 정리하는 시간을 갖고자 한다. 페어분이 내 스터디 그룹과 교류하는 다른 스터디 그룹원 분이셔서 굉장히 편하게 진행할 수 있었다. 인증 / 보안 파트는 매우 중요한데 좋은 페어분을 만나서 다행이다. 페어 프로그래밍하는 시간은 5시까지였으나 모든 수업 다 듣고 저녁 밥 먹은 후 7시부터 9시까지 같이 또 프로그래밍 하면서 우리의 코드를 더욱 단단하게 한 것 같다.

 


[ 오늘의 TODO ]

  1. 코드 스테이츠) HTTPS 개념
  2. 코드 스테이츠) Cookie 개념
  3. 코드 스테이츠) Session 개념
  4. 코드 스테이츠) Pair-Programming
    // im-sprint-auth-session
  5. 패스트 캠퍼스) 인강 3개 이상 듣기 // optional
  6. 스터디 그룹) 프로그래머스 문제 풀기
    // 삼각 달팽이
    // 오픈 채팅방
    // 이제 블로깅 다 작성하면 풀어야 한다. 
  7. 생활) 물 1L 이상 마시기
  8. 생활) 1시간 이상 걷기 
  9. 개선) 페어 프로그래밍할 때도 혼자 있을 때처럼 침착하게 오류 대처하기

[ 오늘의 코드]

1. 쿠키를 어떻게 보내줄 것인가?

   만약에 일반 Node.js 환경에서 구축한 서버라면 HTTP 모듈을 활용했을 것이다. 그 때, 세션을 생성하고 클라이언트에 쿠키를 보내줄 때는 res.setHeader('Set-Cookie', ~~) 로 응답해줬어야 한다. 하지만 express 을 사용한 환경이라면 다르다. express 에는 express-session 이라는 환경이 존재하는데, 이 환경이 알아서 쿠키를 보내줬다. 단, 쿠키를 보내주기 전에 미들웨어로 session( ) 객체 안에 쿠키의 option 들을 다 지정해주어야 했다. 구글링을 하다가 오히려 헷갈렸던 점이 있었는데 그건 cookie-parser 라는 패키지 때문이다. express-session 을 사용하면 더이상 cookie-parser 가 필요하지 않다. 두 번째로 res.cookie 다. 이건 express 기본 내장으로 Express 일반 환경에서, 즉 express-session 을 따로 설치하지 않더라도 사용할 수 있는 메소드다. 이 메소드를 사용함으로써 HTTP 환경일 때 setHeader('Set-Cookie',~ ) 를 구현할 수 있다. 하지만 우리는 express-session 을 설치했기 때문에 따로 사용하지 않아도 됐다. 

 

app.use(
  session({
    secret: '@codestates',
    resave: false,
    saveUninitialized: true,
    cookie: {
      domain: 'localhost',
      path: '/',
      maxAge: 24 * 6 * 60 * 10000,
      sameSite: 'none',
      httpOnly: true,
      secure: true,
    },
  })
);

// ----------------------------------------------

app.use(cors({
  origin: 'https://localhost:3000',
  methods: ['GET', 'POST', 'OPTIONS'],
  // 쿠키를 보내주고 받는 작업할 때 각 서버, 클라이언트는 이 credentials 를 신경써줘야 한다.
  // 클라이언트의 경우 withCredentials 를 true로 설정
  credentials: true,
}));

 

  위의 코드가 기본적으로 세팅을 해준 코드고

 

 else {
 
  req.session.save(function (err) {
    if (err) throw err
    req.session.userId = userInfo.userId;
    res.status(200).json({ data: userInfo, message: 'ok' });
  });
  
  // OR -------------
  
  req.session.userId = userInfo.userId;
  res.status(200).json({ data: null, message: "ok" });
}

 

   바로 위의 코드가 데이터를 보내주는 코드인데, 여기서 req.session.save(function () {~}) 은 따로 작성해주지 않아도 됐다. 공식문서에서도 설명을 해주었다.

2. 쿠키를 어떻게 없애줄 것인가?

  테스트케이스에서는 쿠키를 없애는 방법을 따로 설명해주지 않았지만 로그아웃을 할 때, 쿠키가 없어져야 한다. 하지만, 쿠키가 그대로 남아 있는 것을 확인하고 로그아웃을 구현할 때 쿠키를 없애는 방법을 찾아서 작성했다. 페어분께서 찾아주셨는데, 그 방법은 clearCookie 메소드였다. res.cookie 와 마찬가지로 기본 express 내장 메소드였다. 

 

else {
  req.session.destroy((err) => {
    if (err) throw err;
      req.session = null;
      res
        .clearCookie("connect.sid")
        .status(200)
        .json({ data: null, message: "ok" });
  });
}

 

 

3. 쿠키를 어떻게 서버로 보낼 것인가?

  사실, 이 고민은 할 필요 없는게 쿠키는 알아서 서버를 향해 간다. 그렇다면 우리가 해줘야 할 일은 서버를 통해 보내주는 방법이다. 일단, 코드를 작성할 때부터 HTTPS 일 때만 동작하도록 설정을 했기에 브라우저에 화면을 렌더링할 때도 HTTPS 프로토콜로 열어줘야 한다. package.json 에서 브라우저에 렌더링하는 부분에 HTTPS 인증서가 존재하는 파일 경로를 작성해주었다. 

 

"scripts": {
    "start": "HTTPS=true SSL_CRT_FILE=../server-session/cert.pem SSL_KEY_FILE=../server-session/key.pem react-scripts start",

 

  그 후, 주의해야 하는 부분은 첫 번재로 withCredentials 를 true 값으로 넣어주는 것 정도면 될 것같다. 항상 fetch 를 쓰다가 axios 를 써서 조금 당황하기는 했는데 사용 방법을 보니 fetch 와 별반 다를 것은 없었고 fetch 는 브라우저 API 인 반면 axios 는 Node.js 환경에서도 사용할 수 있으니 axios 를 더 많이 사용하는 것 같다.

 

 axios
  .post(
    `https://localhost:4000/users/login`,
    {
      userId: this.state.username,
      password: this.state.password,
    },
    {
      withCredentials: true,
    }
  )
  .then(() => {
    this.props.loginHandler();
    return axios.get(`https://localhost:4000/users/userinfo`, {
      withCredentials: true,
    });
  })
  .then((res) => {
    this.props.setUserInfo({
      userId: res.data.data.userId,
      email: res.data.data.email,
    });
  })
  .catch((err) => console.log(err));