bcrypt는 애초부터 패스워드 저장을 목적으로 설계되었다. Niels Provos와 David Mazières가 1999년 발표했고 현재까지 사용되는 가장 강력한 해시 메커니즘 중 하나이다. bcrypt는 보안에 집착하기로 유명한 OpenBSD에서 기본 암호 인증 메커니즘으로 사용되고 있고 미래에 PBKDF2보다 더 경쟁력이 있다고 여겨진다. - Naver D2
회원가입 시 password 문자열 그대로 DB에 저장하는것은 사이트가 해킹당할 경우 큰 사고로 이어질 수 있기에 굉장히 위험한 방식이다. 그렇기에 보안성을 높히기 위해서 password를 암호화하게 되는데, bcrypt는 Blowfish를 기반으로 만들어진 단방향 해시 함수를 말한다. 흔히 사용되는 해시 알고리즘인 SHA-256을 사용해서 데이터를 해싱한다.
bcrypt는 단방향 암호화이기 때문에 복호화가 불가능한데, 복호화란 암호화된 문자열을 다시 원래 문자열로 해독하는것을 의미한다.
npm install bcrypt
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
// Store hash in your password DB.
});
});
//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에 저장되었다!