Bcrypt 로 패스워드 암호화하기

싱클베어·2022년 2월 14일
0

Bcrypt 로 패스워드 암호화하기

현재 작업중인 미니 팀 프로젝트에서 사용자 회원가입, 로그인 시 비밀번호가 평문으로 저장되고 있다. 당연히 평문으로 저장하는 것은 그리 좋은 아이디어는 아니기에, Node.js 에서 패스워드를 암호화 할 수 있는 강력한 라이브러리인 Bcrypt를 적용해보았다.

해싱?

hash 라는 단어 자체가 고기, 감자따위를 잘게 다져서 섞는다는 의미이다. 다져진 감자는 다시 감자로 돌아갈 수 없듯이, 해싱을 거친 암호 원본은 다시 원본 형태로 돌아갈 수 없게된다. 즉, 단방향이다.

hash

다져진 감자는 원재료 상태로 돌아갈 수 없다.

Bcrypt에서는 salt 라는 단계를 거쳐, 음식에 소금을 살짝 뿌려 간을 하듯 아주 작은 임의의 랜덤한 텍스트를 추가하여 원본 암호를 변형한다.

Bcrypt 적용

우선 사용자로부터 회원가입 시 비밀번호를 받는다.

// userRoute.js - signup api
router.post("/signup", async (req, res) => {
  try {
    const { loginId, password, nickname } = await postUserSchema.validateAsync(req.body)
    ...
    const user = new Users({ userId: loginId, password, nickname })
    await user.save()
    ...
  } catch(err) {

  }
})

일련의 validation 과정을 거치고, user.save() 를 통해 데이터베이스에 저장한다. 이 때, Mongoose 내에 pre 메서드를 사용하여 저장하기 전에 해싱 과정을 거친다.

// models - user.js
const bcrypt = require("bcrypt")
const saltRounds = 10;

...

userSchema.pre("save", function (next) {
  const user = this; // userSchema

  // user document의 'password' 가 수정되었을 경우. isModified가 document를 새로 추가하는 경우에도 동작함.
  if(user.isModified('password')) { 
    // genSalt : salt 생성
    bcrypt.genSalt(saltRounds, function(err, salt) {
      if (err)
        return next(err);
      bcrypt.hash(user.password, salt, function (err, hashedPassword) {
        if(err)
          return next(err);
        user.password = hashedPassword; // 평문 user.password를 hashedPassword 로 입력
        next(); // save 진행
      })
    })
  } else {
    // password 값이 변경되지 않을 경우
    next();
  }
})

위와 같은 과정을 거쳐, 데이터베이스에 저장 시 해싱된 암호 값이 저장된다.

로그인 시에는, 사용자가 입력한 암호와 해싱된 암호 값을 비교할 수 있는 bcrypt.compare(password, hashed_password) 를 사용한다.

router.post("/login", async (req, res) => {
  try {
    const { loginId, password } = await postLoginSchema.validateAsync(req.body)
    const user = await Users.findOne({ userId: loginId }).exec()
    ...
    // 로그인 시 사용자로부터 입력받은 패스워드와 bcrypt를 거쳐 저장된 패스워드 비교
    const isSamePassword = await bcrypt.compare(password, user.password)
    if(!isSamePassword){
        res.send({
            ok: false,
            result: "ID 또는 패스워드를 확인해주세요.",
          })
          return
    }
    ...
  } catch (err) {
    ...
  }
})

사용자가 입력한 암호를 별도로 변환하지 않고 데이터베이스에 저장된 해시된 비밀번호와 비교할 수 있다.


참고 URL

Node.js 패스워드 암호화 - bcrypt

Node.js : Bcrypt로 비밀번호 해싱(Hashing)하기

profile
안녕하세요.

0개의 댓글