
HTTPS : HTTP 통신을 하는 과정에서 내용을 암호화하여 데이터를 전송하는 방법
[HTTPS가 뭐고 왜 쓰나요? (Feat. 대칭키 vs. 비대칭키)]
https://www.youtube.com/watch?v=H6lpFRpyl14
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 서버에 적용해준다
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)
}
쿠키란 서버에서 클라이언트에 데이터를 저장하는 방법의 하나이다
서버가 원한다면 서버는 클라이언트에서 쿠키를 이용하여 데이터를 가져올 수 있다
그런데 서버가 아무때나 이 쿠키 정보를 가져올 수 있는게 아니다
쿠키가 설정한 옵션이 충족이 되어야 서버는 클라이언트로부터 정보를 가져올 수 있다
조건들은 여러가지가 있다
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하게 유지할 수 있다.
https://www.youtube.com/watch?v=OpoVuwxGRDI

쿠키에 User의 로그인 정보를 저장하면 보안상 위험이 존재하니 Server는 User id, password를 DB에 저장하고 이와 매치되는 session id를 만든 다음 User에게 반환해서 다음 로그인시 쓸 수 있도록 한다.
app.use(
session({
secret: '@codestates',
resave: false,
saveUninitialized: true,
cookie: {
domain: "localhost",
path: "/",
maxAge: 24 * 6 * 60 * 10000,
sameSite: "none",
httpOnly: true,
secure: true,
},
})
);
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형태의 데이터를 문자열로 바꿔주는 역할을 함
},
};
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()
}
},
};
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()
}
},
};