User
를 만들고passowrd
를 저장하는 것까지 만들었다.
그러나 password
가 그대로 노출되어 있어서 아주 위험하다.
절대 DB
에 password
를 저장하면 안된다. 아주 위험한거다.
어떤 회사든지 해킹 당하면 이런 식으로 DB
에 password
를 저장한걸 후회하게 된다.
그리고 보통 사람들은 같은 password
를 여러 사이트에서 사용하기에
예를 들어 instagram
,facebook
,kakaotalk
같은 곳에서 password
를 쓰듯이 말이다.
내일 당장 instagram
이 해킹 당했다고 하면 그런데 이런식으로 password
를 저장했다면
해커가 유출된 email
,password
로 다른 사이트에 로그인하려 할거다.
대부분의 사람들은 같은 password
를 사용하기 때문이다.
그런 피해를 방지 할수 있게 되도로고 같은 password
를 쓰지 않는거다.
그러면 해킹을 당했어도 다른 사이트에서 피해가 생기지 않을테니까 말이다.
만약 서비스에서 password
를 관리하는 사람이라면 이런식으로 DB
에 password
를 저장하지 않으면 된다.
저번 파트에서 말했듯이 유저가 입력한 password
가 뭔지 몰라도 password
가 일치하는지
안하는지 알수 있다. 그래서 암호화 하는게 정말 중요한거다.
수학에 기반되어 있다는 것 빼고는 정말 완벽하다.
그래서 password
를 hash
해볼거다.
블록체인에서 해싱은 어떤건지 password
를 해싱하는 이유 등 많은 정보가 있으니
나중에 찾아 보도록 한다.
해싱은 일방향 함수인데 문자열이 필요하다. 만약에 이런 password
가 있다고 한다면
14856198059174 -> dasfjboiqwenldsmpa
해싱을 하게 되면 이런 문자열로 바꿔 주는 거다.
DB
에 password
를 저장하지 않고 해싱된 password
를 저장 하게 된다.
해싱이 일방향 함수라는 건 정말 중요한거다. 절대 되돌릴수 없다.
위 입력값으로는 위에 나온 출력 값이 나오는 거다. 그런데 출력값으로 입력 값을 알아 낼수가 없다.
입력을 하면 출력 값이 나오는데 출력값으로는 입력값을 알아 낼수 없다.
그리고 같은 입력 값으로는 항상 같은 출력값이 나온다.
해싱을 체험할 수 있는 사이트로 가본다.
https://emn178.github.io/online-tools/sha256.html
사이트 input
입력란에 hello~~~~!!!
라고 입력해 보았다.
그러면 밑에 출력이 해싱처리 되서 나온다.
그리고 그 출력값을 입력 칸에 복붙 해보면 다른 출력 값이 나오게 된다.
절대 입력 했던 값이 나오지 않는다. hello~~~~!!!
라고 입력해야 값은 값이 나온다.
그러니깐 같은 입력값으로는 항상 같은 해싱값이 나온다.
이런걸 컴퓨터 과학에서 deterministic function
(결정적 함수) 라고 한다.
항상 똑같은 결과로 나와서 그런다.
그러면 password
를 가지고 이렇게 만들어 본다.
password
를 이렇게 만들면 다음에 유저가 로그인 할때 어떡해야 할지 궁금할거다.
유저들의 원래 password
를 모르니까 말이다. 물론 원래 password
를 모르지만
password
의 해시값을 알고 있으니까 가능하다.
우선 계정을 만들때
password
를 안전하게 저장하는 것부터 해보도록 한다.
mongo
콘솔에서 db.users.remove({})
를 쳐서 모든 데이터를 지워 본다.
이제 모든 User
를 지웠다. 그릭고 또 새로운 User
를 만들건데 이번에는 password
를 해싱할거다.
해싱할때 사용할건 bcrypt
라는 건데 bcrypt
는 정말 오래전에 만들어졌다.
1999년에 만들어 졌다. 많은 사람들이 사용하고 있다.
그리고 Blowfish cipher
를 기반으로 만들었다. bcrypt
는 정말 똑똑한 사람들이 만들었고,
여러 언어에서 사용할수 있다. 그 중에 하나가 javascript
이다.
https://www.npmjs.com/package/bcrypt
여기 nodeJS
에서 사용할 수 있는 bcrypt
가 있다.
설치해 보도록 한다. npm i bcrypt
복사해서 vsc
터미널에 입력해 준다.
bcrypt
로 password
를 해싱할거다. 해커가 해싱된 password
를 가지고 할수 있는 공격이 있는데
바로 rainbow table
이란거다. rainbow table
도 정보를 한번 찾아 보도록 한다.
그 rainbow table
의 공격을 bcrypt
가 막아준다.
이제 password
를 해싱 해볼건데
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
// Store hash in your password DB.
});
여기 나온대로 사용 하면 된다. myPlaintextPassword
말고도 다른argument
가 하나 더 있는데
saltRounds
가 있다. 말 그대로 소금을 뿌리는 건데 password
를 더 예측하기 어렵게 만든다.
그래서 이 함수를 그대로 사용 할거다.
bcrypt.hash()
쓰고 유저가 입력한 password
를 argument
로 넣을거다.
"12345" 같은 password
를 말이다. 그리고 saltRounds
를 5라 하면
몇번 해싱을 할건지 알려주는 거다. 이렇게 하면 출력값이 나온다.
saltRounds
가 뭐냐면 한번만 해싱 하는것 보다 여러번 하는게 암호화 하기에 더 좋다.
유저가 로그인 할때 password
를 입력할텐데 그 password
를 5번 해싱한 다음에
password
가 일치하는지 비교하는거다. 좀 복잡하게 느껴 질수도 있는데 걱정 할 필요 없다.
천천히 알아가 보도록 한다. 그러면 왜 이렇게 만들었는지 알게 된다.
이제 password
를 해싱 할건데 User
를 저장하기 전에 해싱을 해줄거다.
이전 파트에서 pre("save")
라는걸 했다. 그걸 사용해본다.
User.js
에서
import bcrypt from "bcrypt";
userSchema.pre("save", async function () {
this.password = await bcrypt.hash(this.password, 5);
});
userSchema.pre("save", async function () {
save
를 하기전에 async function
을 사용 할건데 이 안에서 this.password
를 가지고 해싱을 한거다.
그리고 documents
를 확인하면 function
에 콜백 함수를 쓸수도 있다.
mongoose
가 하는 방식이랑 정말 비슷하다. 그리고 promise
도 쓸수 있다.
그래서 then
을 쓰거나 async
,await
를 쓸수 있다.
그 다음 이제 await
를 먼저 쓰고 bcrypt
에서 일단 bcrypt
를 import
해주고
bcrypt.hash()
를 써주고 이 안에 암호화 될 data
를 넣어주면 된다.
암호화 할 data
는 유저가 입력한 password
이다.
왜냐하면 유저가 입력한 password
를 그대로 저장하면 안된다.
암호화할 data
는 password
에 있다. 그러니까 thin.password
라고 쓰면 된다.
기억하자. context
,function
안에서 this
는 create
되는 User
를 가리킨다.
그걸 this
라고 부른다. 여기서 하는건 저장하려는 User
의 password
를
암호화 시킨 다음에 저장하는거다. 그리고 saltRounds
를 넣어 줬다.
await
를 쓰고 있어서 콜백 함수는 필요 없다. 이렇게 해서 암호화 된 password
를 저장하고 있다.
앞으로는 유저가 form
에 입력한 password
로 User
가 저장되지 않고 form
에 입력한
password
를 해싱한 다음에 저장 할거다.
그리고 this.password
를 console.log
해본다.
userSchema.pre("save", async function () {
console.log("Users password:", this.password);
this.password = await bcrypt.hash(this.password, 5);
console.log("Hashed password", this.password);
});
위에서는 User password
를 받고 밑에서는 hassing
된 password
를 받는거다.
이제 계정을 다시 만들어 본다. 잘 작동 할거다.
예전에 Video
를 만들때도 이렇게 했었다. Video
의 hashtags
를 format
하기 위해서 말이다.
이미 한번 했었던 패턴이다. 다시 한번 복습한다. this.password
는 유저가 입력 한
password
를 말한다.
이번에 password
를 "12345"로 해서 만들어 본다. 콘솔 두개다 값이 잘 나오고 있다.
Users password: 12345
Hashed password $2b$05$39HICIb9XG2kHMJNntufcOANiiC6rMkbTzPCmmV2YXC1PKIMb7CIG
mongodb
로 가서 users
를 확인해 본다. 여기에도 해싱 처리되어서 출력된다.
이제 더 이상 password
를 그대로 저장하지 않고 해싱된 password
를 저장한다.
이제 누군가 DB
를 보게 되더라도 password
가 뭔지 모르게 된다.
유저의 정보를 보호해 주는거다. 이제 어떻게 password
를 암호화 하는지 알게 되었다.
절대 password
를 그대로 저장하지 않는다. 항상 해싱 해준다.
userSchema.pre("save")
를 써서 저장하기전에 잠깐 가로채서 작업 할수 있게 만들었다.