보안 전공생의 공부

게시판 만들기 / password 암호화 -bcrypt 본문

WEB/Node

게시판 만들기 / password 암호화 -bcrypt

수잉 2021. 11. 17. 14:14

user의 비밀번호가 그대로 DB에 저장되도록 코드를 작성하였는데,

이는 낮은 보안성이다.

보안성을 높이기 위해서는 비밀번호가 hash처리가 되어야 한다.

 


· hash : hash 알고리즘으로 생성된 값

          결과값과 알고리즘을 알아도 원래 data를 알 수 없다(복원불가)!

function hashFunc(inputNum) {
  var str = inputNum.toString();
  var result = str[0] + str[str.length-1];
  return result;
}

위의 hash알고리즘 함수는 입력된 값의 첫번쨰 자리값+마지막자리값을 return한다.

1을 넣으면 11, 2321을 넣으면 21dl return된다.

 

결과값과 알고리즘(함수)를 알더라도 입력값을 정확히 알 수 없다.

결과값이 12이고 위의 알고리즘이더라도 입력값이 112, 122, 13332, 147289892 처럼 다양한 경우로 예상할 수 있기 때문이다.

 

DB에 password값이 아니라 password의 hash값을 생성하여 저장하도록 해보자.

사용자가 로그인하려고 하면 사용자가 입력한 password에 대해 서버가 hash를 생성하고,

이 값을 DB에 저장한 password hash값과 일치하는지 비교하여 

일치하면 로그인이 된다.

 

 

▶대형사이트가 해킹당하여도 이용자들의 비밀번호는 유출되지 않고, 비밀번호의 hash값이 유출된다.

그래서 해커가 hash값과 hash알고리즘을 이용해 원래의 비밀번호를 알아내는 것은 불가능하다.

하지만 원래 비밀번호와 일치하는 hash값이 나올때까지 hash알고리즘을 반복하면 

원래 비밀번호를 얻을 수 있기 때문에 최대한 빨리 비밀번호를 바꿔야한다.

 

https://www.a-mean-blog.com/ko/blog/%ED%86%A0%EB%A7%89%EA%B8%80/_/Hash

 

토막글: Hash - A MEAN Blog

hash,  hash값 : hash 알고리듬으로 생성된 값hash 알고리듬: hash를 생성하는 알고리듬 예를 들어 12345라는 값을 어떠한 hash 알고리듬을 사용해서 hash를 생성하면 abc라는 값이 된다고 합시다. hash 알고

www.a-mean-blog.com


bcryptjs package를 사용하여 DB에 password를 hash로 변환하여 저장하도록 하자.

 

 

· package 설치

 

· User.js에 코드 수정 및 추가

// models/User.js

var mongoose = require('mongoose');
var bcrypt=require('bcryptsjs');


// schema
var userSchema = mongoose.Schema({
  username:{type:String, required:[true,'Username is required!'], unique:true},
  password:{type:String, required:[true,'Password is required!'], select:false},
  name:{type:String, required:[true,'Name is required!']},
  email:{type:String}
},{
  toObject:{virtuals:true}
});

// virtuals
userSchema.virtual('passwordConfirmation')
  .get(function(){ return this._passwordConfirmation; })
  .set(function(value){ this._passwordConfirmation=value; });

userSchema.virtual('originalPassword')
  .get(function(){ return this._originalPassword; })
  .set(function(value){ this._originalPassword=value; });

userSchema.virtual('currentPassword')
  .get(function(){ return this._currentPassword; })
  .set(function(value){ this._currentPassword=value; });

userSchema.virtual('newPassword')
  .get(function(){ return this._newPassword; })
  .set(function(value){ this._newPassword=value; });

// password validation 
userSchema.path('password').validate(function(v) {
  var user = this; 

  // create user 
  if(user.isNew){ 
    if(!user.passwordConfirmation){
      user.invalidate('passwordConfirmation', 'Password Confirmation is required.');
    }

    if(user.password !== user.passwordConfirmation) {
      user.invalidate('passwordConfirmation', 'Password Confirmation does not matched!');
    }
  }

  // update user 
  if(!user.isNew){
    if(!user.currentPassword){
      user.invalidate('currentPassword', 'Current Password is required!');
    }
    else if(!bcrypt.compareSync(user.currentPassword, user.originalPassword)){
      user.invalidate('currentPassword', 'Current Password is invalid!');
    }

    if(user.newPassword !== user.passwordConfirmation) {
      user.invalidate('passwordConfirmation', 'Password Confirmation does not matched!');
    }
  }
});

// hash password
userSchema.pre('save', function (next){
  var user = this;
  if(!user.isModified('password')){ 
    return next();
  }
  else {
    user.password = bcrypt.hashSync(user.password);
    return next();
  }
});

// model methods
userSchema.methods.authenticate = function (password) {
  var user = this;
  return bcrypt.compareSync(password,user.password);
};

// model & export
var User = mongoose.model('user',userSchema);
module.exports = User;
bcrypt.compareSync(user.currentPassword, user.originalPassword)

bcrypt의 compareSync함수를 통해 DB에 저장된 hash값과 입력받은 password의 hash값이 일치하는지 비교한다.

 

Schema.pre함수는 첫번째 파라미터로 설정된 event인 save가 발생하기 전에 먼저 callback함수를 실행시킨다.

routes/users.js >update부분

save이벤트는 Model.create, Model.save함수 실행 시 발생하는 이벤트이다.

 

create, save 함수가 실행하기 전에 callback함수가 먼저 실행되는 것이다.

isModified함수는 해당 값과 DB에 기록된 값과 비교하여 변경된 경우 true를 반환한다.

-> user 생성,password 수정 시 bcrypt.hashSync함수로 password 값을 hash값으로 바꿈

 

isModified함수는 DB로부터 Model이 생성된 후 해당 값이 변경되었는지를 알려주는 역할을 한다.

DB 상에서는 password 값으로 hash값이 저장되어 있고,

edit을 통해 새로운 password 값을 입력받는 경우 입력받은 값이 그대로 있다.

그렇기 때문에 isModified('password')가 true인 경우 else 구문이 실행되어

해당 값(입력받은 값)을 hash로 변경해주는 것이다.

 

ex) 처음에 password를 '1234'로 입력하여 가입

    > isModified('password')가 true를 반환하여 bcrypt.hashSync가 실행됨 (서버에 hash값으로 변환되어 저장됨)

    > edit으로 new password '5678'을 입력하면

    > isModified('password')값이 ('5678' != 서버의 hash값) : true가 되어 bcrypt.hashSync가 실행됨

       (서버에 5678에 대한 hash값으로 변환되어 저장됨)

Comments