sprint-auth-cookie (쿠키에 대한 모든 것)

flobeeee·2021년 3월 6일
3

Sprint

목록 보기
20/25

🍪 쿠키란

  • 서버가 일방적으로 클라이언트에 전달하는 작은 데이터 (응답헤더에 set-cookie 넣어서)
  • 서버가 웹 브라우저에 정보를 저장하고 불러올 수 있는 수단
  • 쿠키를 이용한다는 것
    : 서버가 클라이언트에게 쿠키 전송 ( + 클라이언트에서 서버로 쿠키 전송)
  • 장시간 보존해야 하는 정보 저장에 적합 (로그인 상태 유지, 사용자 선호 테마 등)
  • 서버는 데이터를 저장한 이후 아무때나 데이터를 가져올 수 없습니다.
    특정 조건이 만족하는 경우에만 다시 가져올 수 있는데, 이런 조건은 쿠키 옵션으로 설정합니다.

🍪 쿠키옵션

  1. Domain
    요청해야 할 URL이 http://www.localhost.com:3000/users/login 이라 하면
    여기에서 Domain은 localhost.com이 됩니다.

    만약 쿠키 옵션에서 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송할 수 있습니다.

  2. Path
    세부 경로는 서버가 라우팅할 때 사용하는 경로입니다. /users/login 입니다.
    명시하지 않으면 기본으로 / 으로 설정되어 있습니다.
    Path 옵션의 특징은 설정된 path를 전부 만족하는 경우 요청하는 Path가 추가로 더 존재하더라도 쿠키를 서버에 전송할 수 있습니다.

    즉 Path가 /users로 설정되어 있는 경우,
    요청하는 세부 경로가 /users/login 인 경우라면 서버로 쿠키 전송 O
    요청하는 세부 경로가 /user/login 인 경우라면 서버로 쿠키 전송 X

  3. MaxAge or Expires
    쿠키가 유효한 기간을 정하는 옵션입니다.
    MaxAge 는 몇 초 동안 쿠키가 유효한지 설정
    Expires 는 언제까지 유효한지 Date를 지정합니다. (클라이언트의 시간을 기준)
    이후 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴됩니다.
    하지만 두 옵션이 모두 지정되지 않는 경우에는 브라우저의 탭을 닫아야만 쿠키가 제거될 수 있습니다.

  4. Secure
    만약 해당 옵션이 true로 설정된 경우, 'HTTPS' 프로토콜을 이용하여 통신하는 경우에만 쿠키를 전송 할 수 있습니다.

  5. HttpOnly
    자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정합니다.
    만약 해당 옵션이 true로 설정된 경우, 자바스크립트에서는 쿠키에 접근이 불가합니다.
    명시되지 않는 경우 기본으로 false로 지정되어 있습니다.
    만약 이 옵션이 false인 경우 자바스크립트에서 쿠키에 접근이 가능하므로 'XSS' 공격에 취약합니다.

  6. SameSite
    Cross-Origin 요청을 받은 경우 요청에서 사용한 메소드와 해당 옵션의 조합으로 서버의 쿠키 전송 여부를 결정하게 됩니다.
    사용 가능한 옵션은 다음과 같습니다.

    • Lax :Cross-Origin 요청이면 'GET' 메소드에 대해서만 쿠키를 전송할 수 있습니다.
    • Strict : Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송 할 수 있습니다.
    • None: 항상 쿠키를 보내줄 수 있습니다. 다만 쿠키 옵션 중 Secure 옵션이 필요합니다.

이러한 옵션들을 지정한 다음 서버에서 클라이언트로 쿠키를 처음 전송하게 된다면 헤더에 Set-Cookie라는 프로퍼티에 쿠키를 담아 쿠키를 전송하게 됩니다.

이후 클라이언트 혹은 서버에서 쿠키를 전송해야 한다면 클라이언트는 헤더에 Cookie라는 프로퍼티에 쿠키를 담아 서버에 쿠키를 전송하게 됩니다.

🍪 쿠키 스프린트 진행(서버)

  1. cert.pem, key.pem 파일들을 server-cookie 폴더에 넣기
  2. index.js 파일을 수정해 https 서버를 구축하고, 적당한 cors 옵션을 작성
//작성한 코드
app.use(cors(
  {origin: `https://localhost:3000`,
  Methods: [`POST`, `GET`, `OPTIONS`],
  credentials: true})); // 다른 도메인간 쿠키 주고받을 수 있게 (서버에서 설정)
  1. .env.example 파일명을 .env로 수정
  2. servers/seeders 폴더를 확인하면 유저정보를 확인가능.
    마이그레이션 하기npx sequelize-cli db:migrate 공식문서참고
  3. controller/users/login.js 에서
    데이터베이스에 해당되는 유저정보가 없는 경우에 대한 에러 핸들링,
    유저정보가 데이터베이스에 존재하는 경우에 대하여 응답에 쿠키를 설정하기
    request.setHeader(name, value) 참고해서 쿠키 설정
// 예시 코드
request.setHeader('Content-Type', 'application/json');
// or
request.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);

// 작성한 코드
res.setHeader(
'Set-Cookie', [
`id=${userInfo.id}; Domain=localhost; Path=/; Secure=true; HttpOnly=ture; SameSite=None;` ]);
  1. controller/users/userinfo.js 에서 받은 쿠키에 유저정보가 존재하는지 확인
  2. controller/users/logout.js 에서 쿠키에 인증정보가 담겨있는 경우, 쿠키를 제거하고 ok 메세지를 리턴. 쿠키에 인증정보가 없는 경우, 에러 메세지를 리턴.

🍪 쿠키 스프린트 진행(클라이언트)

  1. 클라이언트의 package.json 파일의 FILL_ME_IN을 서버에서 사용했던 인증서 파일의 상대경로로 변경
    "start": "HTTPS=true SSL_CRT_FILE=../server-cookie.cert.pem SSL_KEY_FILE=../server-cookie.key.pem react-scripts start",
  2. components/mypage.js 에서 axios (fetch와 유사) 이용하여 로그아웃 버튼 클릭하면 로그아웃 요청을 서버에 보내기
//작성한 코드
const axios = require('axios');

axios.post(
'https://localhost:4000/users/logout', // url
 null,  // data
 { 'Content-Type': 'application/json', // 타입
 withCredentials: true }) // 다른도메인간 쿠키전송 위해 (프론트에서 설정)
.then(function (response) {
  props.logoutHandler();
})
.catch(function (error) {
  console.log(error);
});
  1. components/Login.js 에서 로그인버튼을 클릭하면 post 요청을 보냄 => 로그인 핸들러 함수 호출 => get요청으로 유저정보 받아옴 => 유저정보 업데이트 하는 핸들로 호출 하는 코드 작성
 axios.post('https://localhost:4000/users/login')
  .then(()=>{
    this.props.loginHandler()
  })
  .then(() => {
    axios.get('https://localhost:4000/users/userinfo')
  .then(()=>{
    this.props.loginHandler()
  })
  .then(()=> {
    this.props.setUserInfo()
  })
  })
  .catch(function (error) {
    console.log(error);
  })
  1. 테스트는 다 통과할 것이다. 실제로 어플이 돌아가는 부분은
axios.post('https://localhost:4000/users/login', 
    {userId: this.state.username, 
      password: this.state.password,},
      {withCredentials: true})

이렇게 필요한 부분들을 채워나가면서, 완성시키면 된다.

[로그인화면]

[로그인성공]

profile
기록하는 백엔드 개발자

0개의 댓글