기억 휘발 방지소

[Node.js] bcrypt로 비밀번호를 보호하자 본문

Web/Node.js

[Node.js] bcrypt로 비밀번호를 보호하자

choice91 2021. 9. 22. 15:33
728x90
반응형

📌 해시함수란?

해시함수(Hash Function)은 임의의 길이의 데이터를 고정된 길이의 데이터를 매핑하는 함수이다.
출처: 위키백과

해시함수는 단방향 암호화라고도 한다.

단방향 암호화란 A가 해시함수를 거쳐 B가 나왔다고 했을 때 B를 가지고 다시 A를 알아낼 수 없다! (반대의 개념으로 양방향 암호화가 있는데 양방향 암호화는 A를 B로 암호화하고 B를 다시 복호화하여 A를 알아낼 수 있다.)

또한 어떤 입력에 대해서 항상 같은 결과가 나온다.

 

보통 회원가입을 할 때 비밀번호를 DB에 저장할 때 해시함수를 거친 결과값을 DB에 저장한다.

그렇게 하면 DB를 누군가 해킹했을 때 해시함수를 갖고 비밀번호를 역으로 알아낼 수 없다!!

 

📌 bcrypt

bcrypt는 해시함수 중 하나이다.

자바스크립트 뿐만 아니라 C, C++, Java, Python 등 다양한 언어에서 사용할 수 있다.

 

설치

npm i bcrypt

 

📌 bcrypt로 비밀번호 암호화하기 - bcyrpt.hash

// User.js
import mongoose from "mongoose";

const userSchema = new mongoose.Schema({
  email: { type: String, required: true, unique: true },
  username: { type: String, required: true, unique: true },
  password: { type: String, required: true },
});

const User = mongoose.model("User", userSchema);

export default User;

아래 코드처럼 form으로 입력받은 실제 비밀번호를 DB에 그대로 저장하게 되면 비밀번호가 그대로 노출되기 때문에 암호화를 반드시 해야한다.

// userController.js
import User from "./models/User";

export const postJoin = async (req, res) => {
  const { email, username, password } = req.body;
  await User.create({
    email,
    username,
    password,
  });
  return res.redirect("/login");
};

 

bcrypt로 해시를 만드는 함수는 다음과 같다.

유저가 입력한 패스워드가 myPlaintextPassword자리에 들어가며 saltRounds는 몇 번 해싱할건지를 의미한다.

bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
    // Store hash in your password DB.
});

async/await를 쓸 수도 있다.

async function checkUser(username, password) {
    //... fetch user from a db etc.

    const match = await bcrypt.hash(password, saltRounds);

    //...
}

 

 

미들웨어에 bcrypt를 적용했다.

5번 해싱을 하도록 했다.

// User.js
import mongoose from "mongoose";
import bcrypt from "bcrypt";

const userSchema = new mongoose.Schema({
  // ...
});

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);
});
// ...

결과를 보면 위가 유저가 입력한 값이고 아래가 해싱된 값이다.

Users password: 1234
Hashed password: $2b$05$GdBICVsSamyiYd8/UMxffuSeFTEniBM8BYTOmyJy9ZVCT8H3Eareu

 

📌 bcrypt.compare

DB에 실제 비밀번호가 아니라 해시값이 저장되어 있다. 그렇기 때문에 로그인할 때 실제 비밀번호가 아니라 해시값으로 비교를 해서 비밀번호 일치 여부를 따져봐야한다.

이때 bcrypt.compare를 사용해 비교하면 된다!

아래 코드처럼 사용하면 된다고한다.

async function checkUser(username, password) {
    //... fetch user from a db etc.

    const match = await bcrypt.compare(password, user.passwordHash);

    if(match) {
        //login
    }

    //...
}

예시

bcrypt.compare의 첫 번째 매개변수는 사용자가 입력한 비밀번호이고 두 번째 매개변수는 User.findOne으로 DB에서 검색한 user 데이터의 비밀번호를 넣어줘서 두 값을 비교하고 일치하면 true를 반환하고 일치하지 않으면 false를 반환하게 된다.

 

조건문으로 일치하지 비밀번호가 일치하지 않는 경우 처리할 일을 구현해줬다.

export const postLogin = async (req, res) => {
  const { username, password } = req.body;
  const user = await User.findOne({ username });
  
  // ...
  
  const ok = await bcrypt.compare(password, user.password);
  if (!ok) {
    // ...
  }
  
  return res.redirect("/");
};
728x90
반응형

'Web > Node.js' 카테고리의 다른 글

[Node.js] multer  (0) 2021.09.27
[Node.js] express-session  (0) 2021.09.23
[Node.js] mongoDB Schema 생성  (0) 2021.09.18
[Node.js] mongoDB를 연결해보자  (0) 2021.09.17
[Node.js] express.urlencoded는 뭘까?  (0) 2021.09.16