1. 쿠키(Cookie) VS 세션(Session)
쿠키는 로컬이고 세션은 서버에 저장 되는 것
쿠키는 웹브라우저에서 확인가능하지만 서버는 확인 불가능함
따라서 서버가 보안측면에서 더 우수하고
세션은 서버에 저장되어있으니 서버까지 갔다와야하지만 쿠키는 서버에 갔다올 필요가 없으니 속도는 쿠키가 더 빠르다
그래서 로그인 정보와 같은건 세션을 주로 사용한다.
2. 환경변수 설정
index.js
.env
이렇게 갣발에 필요한 비밀번호 같은 것들을 .env파일에 저장해서 불러와서 관리를 하면 편하다..
근데 이거 github에다가는 올리면 안됨...절대로!!
이런식으로 포트번호를 .env파일에 저장해서
이렇게 저장하면
http://localhost:8000이렇게 포트번호가 연결된다.
응용을 하자면 쿠키에 대한 비밀번호인 COOKIE_SECRET_KEY나, 세션에 대한 비밀번호인 SESSION_SECRET_KEY같은 것들도 .env파일에 저장해서 관리가 가능하다
세션 미들웨어 등록시에
.env파일에
이렇게 설정을 했다면
(이건 dotenv 모듈을 사용하겠다고 하는거임 근데 config저거 안붙이면 사용 못한대요..)
cross-env
서로다른 운영체제간에 환경변수를 관리할 수 있도록 해줌
package.json에서
"start":"cross-env NOT_ENV=developement node index",
진입점 파일이 어느위치이지 개발자가 찾지 않아도 된다.
3. 암호화
비밀번호 암호화
비밀번호 암호화 방식에는 두가지가 있다.
암화화??
평면--> 암호문으로 변환하는 과정, 암호문을 남들이 쉽게 남들이 알아볼 수 없도록 하는 것이 암호문의 목적이다..
암호화 방식 1. 단방향: 암호화 한 내용을 복호화 불가--> 원래 데이터로 돌아갈 수 없다!
암호화 방식 2. 양방향 암호화 한 내용을 복호화(암호문->평문) 해서 확인 가능
1) 단방향 암호화
해시함수를 통해서 구현함. 동일한 데이터에 대해서는 항상 동일한 해시값이 생성됨
그런데, 1234를 암호화 한 값과 12345를 암호화 한 값이 같을 수 있는데 이런걸 암호화 충돌이라고 한다 하지만 암호화 충돌이 발생할 가능성은 매우매우 낮다고함..
미세한 데이터 변화에도 해시값은 완전히 달라진다
예를 들어 원문이 12345가나다라마, 12345갸나다라마 라고 한다면 모음하나의 차이이지만 암호화된 데이터의 차이는 험청나게 크다..
그런데 해시란?? 특정한 해시함수에 의해 얻어지는 값이다. 해시함수는 해시 알고리즘이다
키는 복화하기 전의 평문, 해시값은 암호화된 결과 값(매핑 후 데이터 값) , 해싱은 매핑 하는 과정을 일컫는다.
해시 알고리즘은 크게 두가지이다.SHA-256,512이렇게 두가지로 나눠지는데,
256과 512는 여기에서 비트수를 나타낸다.
512가 더 큰 비트를 갖기 때문에 더 안전한 해시 알고리즘이라 볼 수 있다.
충돌 저항성이 약해서 mD5와 SHA-1은 사용하지 않는다고 한다.
2) 양방향암호화 -대칭키, 비대칭키(=공개키)
복호화까지 가능한 방식
공개키와 대칭키 암호화를 조합
https와 같은 프로토콜도 양방향 암호화 사용
대칭키는 암호화,복호화 시에 사용하는 키가 동일하다--> 즉 이 키가 유츨되면 누구나 원본 데이터를 볼 수 있게된다.
키에 대한 관리가 매우 중요하다
AES블록 암호화 운용모드
-ECB 각 데이터 블록을 독립적으로 암호화
-CBC: XOR연산(둘중 하나만 참일떄 참)
공개키 암호화 알고리즘(=비대칭키)
암호화와 복호화에 사용되는 키가 다르다
공개키, 개인키 2개의 키를 사용한다(공개키가 다른 사람과 공유, 개인키는 소유자만 가지고 있어야한다)
공개키로 평문->암호문 암호화
개인키로 암호문->평문 복호화
공개키로 암호화된 데이터는 개인키로만 복호화 할 수 있음.
그래서!! 비밀번호를 DB에 저장할 때에는 단방향 암호화를 사용하는 경우가 많다.
실제로 실습해보자..!
Crypto
내장모듈이라 따로 설치할거 없음
Bcrypt
-해시가 느리고 비용이 많이 들어서 강력한 보안이 필요할 떄 적합하다고 한다.
강력한데 사용은 쉽다.
내장모듈이 아니라서 npm i bcrypt 해서 설치해야한다.
4. Bcrypt를 사용한 실습!!
1. mvc패턴!
우선 이렇게 mvc패턴을 짜줍니다!
다음으로 데이터 베이스를 만들어주고..
config.json파일
이렇게 정의해주고
sequelize를 쓸 거니까
이렇게 models/index.js를 해서 db를 내보냅니다.
database table user는 models/user.js에서
이렇게 만들어서 모듈을 내보냅니다.
그러면 이렇게 내보낸 모듈을 controller에서 사용해야하니까
이렇게 받아와서 객체구조분해로 User를 받아오면 되겠죠?
그리고 우리가 이번시간에 배운 암호화에 대해서 알아보도록 하겠습니다.
bcrypt모듈을 사용해서 유저에게 받은 비밀번호를 암호화해서 저장하도록 하는 기능을 구현해보도록 하겠습니다.
bcrypt모듈을 사용하면 이렇게 간단하게 비밀번호를 암호화하고, 비교할 수 있어요!
그럼 이렇게 비밀번호를 암호화하는 함수와 비교하는 함수를 객체로 묶어서 내보내고~
컨트롤러에서 이 함수를 사용할거니까
이렇게 불러오면 되겠죠??
다음으로는 세션과 관련한 기능들을 알아보도록 하겠습니다.
로그인을 하지 않았다면 왼쪽처럼, 했다면 오른쪽 처럼 보이도록 할 겁니다!
일단 route를 이렇게 정의해주고
getLogin요청이 들어오면 login.ejs 를 보여줄 수 있도록 컨트롤러에서
이렇게 해줍니다. 그리고 post요청으로 login이 들어왔을 때 로그인기능을 구현해보았는데요!
login.ejs파일은 다음과 같이 구성하였습니다.
<!DOCTYPE html>
<html lang="en">
<%- include('./head') %>
<body>
<h1>로그인</h1>
<form onsubmit="login(event)">
<input type="text" id="userid" placeholder="아이디" />
<input type="password" id="pw" placeholder="비밀번호" />
<button type="submit">로그인</button>
</form>
<br />
<a href="/">홈</a>
<a href="/register">회원가입</a>
<script>
async function login(event) {
event.preventDefault(); // 기본 제출 멈춤
try {
const res = await axios({
method: "POST",
url: "/login",
data: {
userid: document.querySelector("#userid").value,
pw: document.querySelector("#pw").value,
},
});
if (res.data.result) {
alert(`${res.data.data.name}님 로그인 성공`);
document.location.href = "/";
} else {
alert(`${res.data.message}`);
document.location.reload();
}
} catch (error) {
console.log(error);
}
}
</script>
</body>
</html>
여기에서 일단 데이터에 해당하는 유저가 있는지 찾아보아야 하니까...컨트롤러에서는
위에서 부터 설명을 해보자면 axios로 post요청을 날렸고, req가 사용될 서버로 /login을 설정해줬습니다. 그리고 돔을 사용해서 위의 폼태그에서 입력받은 값들을 각각 userid,pw로 묶어서 data로 보냅니다.
아 그리고 여기에서 res.json이라고 되어있는데요... res.render는 많이 썼는데, 기억이 잘 안나서 찾아보았습니다,,ㅎ
node.js res.render와 res.json의 사용 차이점 풀어보기 | by Ryan Kim | Medium
그런데 여기서 주의해야 할 점!!!!!! 컨트롤러로 가는건 post요청을 보냈으니 req.body로 받게 됩니다!!!!! req.data가 아닙니다!!!그러니까 저 res.data라는건 이 /login경로에서 만 쓸 수 있는거에요... 이거 저도 헷갈려서 계속 오류났었어요...Request Config | Axios Docs (axios-http.com)
헷갈리신다면 여기 찬찬히 읽어보세요.. 영어로 나와있긴하지만 도움이 되긴합니다...
아무튼 그렇고 그럼 req.body로 받은 걸 객체 구조분해를 통해서 userid,pw로 받아오고 이 userid와 pw는 유저로 부터 입력된 값이겠죠?? 이걸 이제 try-catch구문으로 해결해보도록 하겠습니다.
우선 User 테이블에 해당하는 유저가 있는지 찾아야하죠? 없으면 회원이 아닌거니까요... 그래서 우선 findOne으로 입력된 userid가 테이블에 동일한 userid가 있는지 찾아서 해당하는 row를 user라는 객체에 저장을 합니다.
그럼 해당하는 user가 있었다면 user라는 객체에 {id: '숫자',pw:'어쩌고',name:'어쩌고',userid:'어쩌고'}이런식으로 저장이 되겠죠?
만약에 없다면?? 존재하는 사용자가 없습니다가 떠야합니다!
그래서~~
if문의 구조를 설명하자면 일단 크게 유저가 있으면 비번일치하는지를 확인하고 일치하면 세션을 생성하도록합니다.
세션을 생성하기 위해서는 !!
app.js 파일에서
이렇게 express-session모듈을 불러와서 session이라는 변수에 저장하고 이 session을 사용하기 위해서 다음과 같이 정의해주어야 합니다!
그럼 이제 session이라는 변수를 사용해서 세션을 생성할 수 있어요!
그럼 위의 if문이 이해되시죠?? result라는 변수는 비밀번호를 암호화하고 데이터베이스에는 현재 유저가 회원가입시 입력한 비밀번호가 암호화되어 저장되어있고, 입력받은 비밀번호도 암호화해서 하는 함수를 아까 encrypt파일에서 정의한걸 불러와서 그 함수모듈을 우리가 사용할 수 있으니까 써주고~~ 그럼 이제
res.json({ result: true, data: user });
이렇게 해서 보내줍니다.
그러면 아까전에 post요청 보낼때 /login 경로에서 res.data.result에는 true가 , data에는 데이터베이스에서userid를 기준을 찾아낸 user에 대한{ id, name, pw, userid }가 실려있겠죠?
그러면 여기에서 name만 사용하고 싶으면 res.data.data.name을 해야겠죠?? 저도 한참 헤맸습니다...헷갈리더라구요^^
그래서 이제 로그인 성공메시지를 띄우고, 경로는 기본 홈경로로 돌아간다고 보면 됩니다.
그럼 비번을 틀렸을때는요?
res.data.result=false가 되겠고, res.data.message는 '비밀번호가 틀렸습니다'가 되겠죠? 이렇게 로그인 기능을 구현해보았습니다!!!!
그럼 이렇게 세션이 설정된 1분동안은 홈에서 로그인 전에는 없었던
'내 프로필'이라는 태그가 생겨야 합니다.
그걸 index.ejs에서는
이렇게 되어있는데요! 저 data 뭔지 컨트롤러에서 봐야겠져..?
아까전에 로그인을 해야 세션이 생기는거였잖아여?? 근데 로그인이 안되었다면 data가 null인 채로 index.ejs에 전달되겠죠? 그럼 내 프로필이라는게 안보이겠죠?
그럼 반대로 로그인에 성공해서 세션이 설정되었다면 data는 true가 되니까 '내프로필'이라는게 보이게 됩니다!
오늘은 세션과 암호화를 배워서 그와 관련된 기능들을 위주로 포스팅을 해 보았습니다...
이걸 쓰고 있는 시점에는 이미 프로젝트가 시작되어서 과거의 시점으로 돌아가 작성을 해보았는데요. 과거와 현재가 공존하는 그런 포스팅이네요. 항상 그러긴 했지만,,ㅎ
프로젝트 포스팅은 밀리지 않도록 해 볼게요
그럼 아디오스.
'[새싹X코딩온]웹 풀스택' 카테고리의 다른 글
[새싹X코딩온]웹 풀스택 11주차(9/25)회고록|React-환경설정, Component, Props (1) | 2023.09.26 |
---|---|
[새싹X코딩온]웹 풀스택 7주차(9/1)회고록|Rest API & DB응용 & cookie (1) | 2023.09.03 |
[새싹X코딩온]웹 풀스택 7주차(8/30)회고록|Sequelize (0) | 2023.09.02 |
[새싹X코딩온]웹 풀스택 7주차(8/28)회고록|MVC에 MySQL연결하기 (1) | 2023.09.02 |
[새싹X코딩온]웹 풀스택 6주차(8/25)회고록|MYSQL+MVC패턴 (0) | 2023.08.30 |