[개발심화] https, cookie, session - 7주차 (3)

Hong·2022년 10월 29일
0
post-thumbnail

📡 https란 무엇인가

HTTPS : HTTP 통신을 하는 과정에서 내용을 암호화하여 데이터를 전송하는 방법

[HTTPS가 뭐고 왜 쓰나요? (Feat. 대칭키 vs. 비대칭키)]
https://www.youtube.com/watch?v=H6lpFRpyl14



📡 https사설인증서 발급 및 서버구현

mkcert라는 프로그램을 이용해서 로컬환경(내 컴퓨터)에서 신뢰할 수 있는 인증서를 만들 수 있다

brew install mkcert

mkcert install

mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1
//이렇게 하면 cert.pem, key.pem이라는 파일이 생성됨


📡 HTTPS 서버작성

생성한 인증서 파일을 HTTPS 서버에 적용해준다
express.js를 이용해서 만들어줬다

const express = require('express');
const fs = require('fs');
const https = require('https');


let server;

// 인증서 파일들이 존재하는 경우에만 https 프로토콜을 사용하는 서버를 실행합니다.
// 만약 인증서 파일이 존재하지 않는경우, http 프로토콜을 사용하는 서버를 실행합니다.
// 파일 존재여부를 확인하는 폴더는 서버 폴더의 package.json이 위치한 곳입니다.
if (fs.existsSync("./key.pem") && fs.existsSync("./cert.pem")) {
  server = https
    .createServer(
      {
        key: fs.readFileSync(__dirname + `/` + 'key.pem', 'utf-8'),
        cert: fs.readFileSync(__dirname + `/` + 'cert.pem', 'utf-8'),
      },
      app
    )
    .listen(PORT);
} else {
  server = app.listen(PORT)
}



🍪 cookie란 무엇인가

쿠키란 서버에서 클라이언트에 데이터를 저장하는 방법의 하나이다
서버가 원한다면 서버는 클라이언트에서 쿠키를 이용하여 데이터를 가져올 수 있다
그런데 서버가 아무때나 이 쿠키 정보를 가져올 수 있는게 아니다
쿠키가 설정한 옵션이 충족이 되어야 서버는 클라이언트로부터 정보를 가져올 수 있다
조건들은 여러가지가 있다

1.Domain

url이
https://www.google.com/users/login
이면 도메인은 서브 도메인 정보, 세부 경로를 포함하지 않은 google.com이다. 이 도메인 정보를 충족해야 쿠키를 보내줄 수 있도록 설정할 수 있다.

2.Path

https://www.google.com/users/login
여기서 Path는 /users/login이다 이 Path정보를 충족해야 쿠키를 보내줄 수 있도록 설정할 수 있다. 근데 이 Path는 설정해놓은 조건이 충족된다면 뒤에 다른 Path가 추가적으로 들어와도 상관이 없다.

3.MaxAge or Expires

쿠키가 유효기간을 정하는 옵션이다.
MaxAge는 앞으로 쿠키가 몇 초 동안 유효한지 설정하고
Expires는 앞으로 쿠키가 몇 날 동안 유효한지 설정한다(Date)

4.Secure

쿠키를 전송할 때 사용하는 프로토콜에 따라 쿠키 전송 여부를 결정시킬 수 있다 만약 이 값이 true면 HTTP프로토콜을 사용할 때만 전송하도록 하게 한다.

5.SameSite

요청에서 사용한 method와 아래의 해당 옵션의 조합으로 쿠키 전송 여부를 설정할 수 있다.
Lax : Cross-Origin 요청이면 'GET'메소드에 대해서만 쿠키를 전송할 수 있다.
Strict : Cross-Origin이 아닌 same-site인 경우에만 쿠키를 전송 할수 있다.
None : 항상 쿠키를 보내줄 수 있다. 다만 이 옵션을 사용하기 위해서는 Secure옵션이 필요하다.

이렇게 쿠키의 옵션을 이용해서 서버는 클라이언트에 인증정보를 담은 쿠키를 전송하고, 클라이언트는 전달받은 쿠키를 서버 요청과 같이 전송하여 stateless한 인터넷 연결을 stateful하게 유지할 수 있다.




📀 session이란 무엇인가

[쿠키, 세션, 캐시가 뭔가요?]

https://www.youtube.com/watch?v=OpoVuwxGRDI


session기반 로그인 인증 프로세스


쿠키에 User의 로그인 정보를 저장하면 보안상 위험이 존재하니 Server는 User id, password를 DB에 저장하고 이와 매치되는 session id를 만든 다음 User에게 반환해서 다음 로그인시 쓸 수 있도록 한다.




👾 코드를 통해 살펴보자

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,
    },
  })
);

login process를 백엔드에서 처리하는 모듈이다

const { userinfo } = require(".");
const { Users } = require("../../models");

module.exports = {
    post: async (req, res) => {
        // userInfo는 유저정보가 데이터베이스에 존재하고, 완벽히 일치하는 경우에만 데이터가 존재합니다.
        // 만약 userInfo가 NULL 혹은 빈 객체라면 전달받은 유저정보가 데이터베이스에 존재하는지 확인해 보세요.
        
        const userInfo = await Users.findOne({
            where: { userId: req.body.userId, password: req.body.password },
        });

        // console.log(userInfo);를 통해 userInfo가 어떤 데이터로 이루어져 있는지 확인한다. , console.log(req.session);를 통해 session이 어떻게 생겼는지 확인해 볼 수도 있다. 여기에는 cookie밖에 없는데 아래에 login이라는 key값의 객체를 하나 만들어 주고 데이터를 삽입할 것이다.
      
        /*
        Users {
            dataValues: {
            id: 1,
            userId: 'kimcoding',
            password: '1234',
            email: 'kimcoding@codestates.com',
            createdAt: 2020-11-18T10:00:00.000Z,
            updatedAt: 2020-11-18T10:00:00.000Z
        }, ...more
        */
       
        //이렇게 나온 userInfo형태에서 password를 제외한 id, email, createdAt, updatedAt을 session객체의 login부분에 넣어준다

        if (userInfo) {
            // userInfo가 있는 경우
            // req.session.login에 넣어야함 그리고 저장해준 다음(save), ok응답을 보내줌

            req.session.login = {"userid" : userInfo.userId, "email" : userInfo.email, "createdAt" : userInfo.createdAt, "updatedAt" : userInfo.updatedAt}
            req.session.save()
            return res.json({"message" : "ok"}).end()
        } else {
            // userInfo가 없는 경우
            // not authorized응답을 보내줌
            return res.json({"message" : "not authorized"}).end()
        }

        //<참고>
        //json은 메소드, 그냥 바꿔주는 기능은 없고 json형식으로 데이터를 보내겠다는 것만 말함
        //JSON.stringify 는 라이브러리를 사용한거임 JSON.stringify는 JSON형태의 데이터를 문자열로 바꿔주는 역할을 함
    },
};

logout process를 백엔드에서 처리하는 모듈이다

module.exports = {
  post: (req, res) => {

    // 앞서 로그인시 세션 객체에 저장했던 값이 존재할 경우, 이미 로그인한 상태로 판단할 수 있습니다.

    // console.log(req.session)를 통해 session이 어떤 형태의 데이터로 이루어져 있는지 확인할 수 있다.
    // 1.만약 login정보가 있다면 login과 cookie객체가 두개 있을 것이고
    // 2.없다면 cookie객체만 있을 것이다
    // 이러한 분기에 따라 로그아웃이 가능할 때와 가능하지 않을 때를 구별해서 다른 메세지와 응답, 상태를 보내줄 수 있다.

    if (!req.session.login) {
      // req.session.login에 만약 로그인 정보가 없다면 로그아웃 자체가 불가능 함으로 400의 상태와 not authorized 메세지를 보내준다.

      return res.status(400).json({"message" : "not authorized"}).end()
    } else {
      // TODO: 로그아웃 요청은 세션을 삭제하는 과정을 포함해야 합니다.
      
      // 만약 req.session.login에 정보가 있다면 로그아웃을 해줘야 한다.
      // 로그아웃이란 로그인 정보를 없애는 것임으로 session.login에 저장되어 있던 정보를 빈 객체로 만들어준다(데이터를 삭제해줌) 그리고 저장해 준다.
      // 마지막으로 200의 상태와 ok라는 메세지를 응답으로 보내준다.

      req.session.login = {};
      req.session.save()
      return res.status(200).json({"message" : "ok"}).end()
    }
  },
};

user가 서버에 user information을 request했을 때 process를 처리하는 모듈이다

const { Users } = require("../../models");

module.exports = {
    get: (req, res) => {

        //client가 userInfo를 요청할 수 있다. 근데 userInfo(login정보)가 있는 경우가 있고 없는 경우가 있으니 이것을 구별해서 적어준다.

        if (!req.session.login) {
            // client가 서버에 요청을 했는데 session에 login정보 자체가 없는 경우
            // 400의 상태와 not authorized메세지를 보내준다. + data가 null(비어있다)라고 알려준다

            return res.status(400).json({"message" : "not authorized", data : null}).end()
        } else {
            // TODO: 세션 객체에 저장되어 있는 사용자 정보를 반환합니다.

            // client가 서버에 요청을 했는데 session에 login정보 자체가 없는 경우
            // 200의 상태와 ok메세지를 보내준다. + client가 userInfo(login정보)를 요청했음으로 data로 session에 저장되어 있는 login정보의 userid를 보내준다.
            return res.status(200).json({"message" : "ok", data : {userid : req.session.login.uid}}).end()
        }
    },
};
profile
Notorious

0개의 댓글