[TIL] bcrypt. 비밀번호를 암호화 해봅시다! feat.Node JS 🦖

June hyoung Park·2020년 8월 28일
2

NodeJs

목록 보기
5/9
post-thumbnail

bcrypt

bcrypt는 애초부터 패스워드 저장을 목적으로 설계되었다. Niels Provos와 David Mazières가 1999년 발표했고 현재까지 사용되는 가장 강력한 해시 메커니즘 중 하나이다. bcrypt는 보안에 집착하기로 유명한 OpenBSD에서 기본 암호 인증 메커니즘으로 사용되고 있고 미래에 PBKDF2보다 더 경쟁력이 있다고 여겨진다. - Naver D2

회원가입 시 password 문자열 그대로 DB에 저장하는것은 사이트가 해킹당할 경우 큰 사고로 이어질 수 있기에 굉장히 위험한 방식이다. 그렇기에 보안성을 높히기 위해서 password를 암호화하게 되는데, bcrypt는 Blowfish를 기반으로 만들어진 단방향 해시 함수를 말한다. 흔히 사용되는 해시 알고리즘인 SHA-256을 사용해서 데이터를 해싱한다.

bcrypt는 단방향 암호화이기 때문에 복호화가 불가능한데, 복호화란 암호화된 문자열을 다시 원래 문자열로 해독하는것을 의미한다.

설치

npm install bcrypt

Basic expample

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

example with MongoDB

//index.js
...

app.post("/register", (req, res) => {
  console.log(req.body);
  const user = new User(req.body);

  // Save-Data-Base
  user.save((err, doc) => { 
    // .save가 처리되기전 패스워드 해싱이 이뤄진다. 해싱은 바로 아래의 User.js에 확인 가능.
    if (err) return res.json({ success: false, err });
    return res.status(200).json({
      success: true,
    });
  });
});

...
//User.js
...
import bcrypt from "bcrypt"; //모듈 불러오기
...
const userSchema = mongoose.Schema({ //User모델의 스키마 정의.
 ...
  password: {
    type: String,
    minlength: 5,
  },
 ...
});

userSchema.pre("save", function (next) { 
  //~.pre()를 통해 해당 스키마에 데이터가 저장되기전(.save) 수행할 작업들을 지정해줄 수 있다.
  var user = this;
  if (user.isModified("password")) { //패스워드가 변경될때만 해싱작업이 처리됨.
    bcrypt.genSalt(10, (err, salt) => {
      if (err) return next(err);
      bcrypt.hash(user.password, salt, (err, hash) => {
        if (err) return next(err);
        user.password = hash;
        next();
      });
    });
  } else {
    next();
  }
});

...

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

먼저 import bcrypt from "bcrypt"으로 bcrypt 모듈을 불러온다. (보통 NodeJS에선 Common JS의 require 구문을 사용하지만, Babel을 통해 ES6의 import 구문을 사용할 수 있게끔 해주었기 때문에 import 구문을 사용해도 에러가 뜨지않는다.)

const userSchema = mongoose.Schema({~~})로 user라는 스키마를 정의해주었는데,
하단의 userSchema.pre("save", function (next) {~~를 통해 userSchema에 데이터가 save되기전 수행할 작업을 지정해줄 수 있다. save다음번째에 위치한 두번째 인자에 들어있는 next콜백은 save전에 수행할 작업을 마치고 save로 넘어가는 콜백함수이다.

   bcrypt.genSalt(10, (err, salt) => {
      if (err) return next(err);
      bcrypt.hash(user.password, salt, (err, hash) => {
        if (err) return next(err);
        user.password = hash;
        next();

먼저 .genSalt()을 통해 salt값을 생성하게 되는데, 인자로 saltRounds와 콜백함수를 받는다. 첫번째 인자인 saltRounds를 통해 bcrypt 해시를 계산하는 데 필요한 시간을 제어할 수 있으며, saltRounds가 높을수록 더 많은 해싱 라운드가 수행되게 된다.

그후 생성된 salt 값은 콜백 함수의 인자로 bcrypt.hash에 넘어가게 되고, 세번째 인자인 콜백함수의 hash값을 user의 password에 넣어주면 된다.

테스트를 위해 Postman으로 해당 api에 post요청을 보내준다.

패스워드가 암호화되어 DB에 저장되었다!

profile
Take me home~~~~

0개의 댓글