본문 바로가기
개발/Node.js

[Node.js] 익스프레스에서 몽고디비 사용법 4 - 비밀번호 암호화

by 윤호 2021. 1. 8.

저번 몽고디비 사용법 3에 이어서 알아보겠습니다.

목표

  • 암호화 과정
  • 몽구스 스키마의 virtual 메소드
  • 비밀번호 암호화하여 저장

암호화 과정

데이터베이스를 암호화 하여 저장하기 위해선 다음과 같은 절차가 필요합니다.

1. 사용자로부터 비밀번호를 받음

2. 암호화를 위한 salt 값을 생성함

3. 비밀번호를 암호화 함

4. 암호화한 비밀번호와 salt 값을 저장

 

암호화하기전 비밀번호를 받기위해 virtual 메소드를 사용합니다. 이를 사용하면 스키마에 가상으로 속성을 설정하여 값을 받을 수 있습니다. 그리고 virtual 메소드 내에서 받은 값을 암호화하여 데이터베이스에 저장할 수 있습니다.

 

salt 값은 암호화를 위한 key입니다. 같은 비밀번호, 같은 salt를 encryptPassword 메소드에 입력하면 동일한 값을 반환합니다. 로그인할 때를 위해 이 salt값도 암호화된 비밀번호와 함께 저장합니다.

몽구스 스키마의 virtual 메소드

몽고디비 사용법 3에서 스키마에 static 메소드를 추가한 것과 같이 virtual 메소드를 추가할 수 있습니다.

다음은 id와 name 속성을 갖는 UserSchema에 info라는 가상 속성을 설정해 id와 name 속성을 저장하는 예제입니다.

UserSchema = mongoose.Schema({
	id : String,
    name : String
});

UserSchema
    .virtual('info')
    .set(function(info){
        var splitted = info.split(' ');
        this.id = splitted[0];
        this.name = splitted[1];
    })
	.get(function(){ return this.id + ' ' + this.name});

...
var user = new UserModel({'info': 'jjang01 짱구'});
user.save();

 

해당 예제는 다음과 같이 id와 name 속성을 통해 user를 저장하는 것과 동일하게 작동합니다.

var user = new UserModel({'id': 'jjang01', 'name': '짱구'});
user.save();

 

get은 user.info를 호출 했을 때 반환하는 값을 설정합니다.

console.log(user.info) // 'jjang01 짱구' 출력 
console.log(user.name + ' ' + user.id) // 'jjang01 짱구' 출력

비밀번호를 암호화하여 저장

먼저 % npm install crypto --save 명령어로 암호화를 위한 encrypt 모듈을 설치합니다.

 

다음과 같이 스키마와 스키마 객체의 메소드를 정의합니다.

UserSchema = mongoose.Schema({
    id: {type: String, required: true, unique: true},
    hashed_password : {type: String, required: true, 'default': ' '},
    salt : {type: String, required: true},
});

// password 를 virtual 메소드로 정의 : 몽고디비에 저장되지 않는 편리한 속성. 특정 속성을 지정하고 set, get 메소드를 정의
UserSchema
    .virtual('password')
    .set(function(password){
    this._password = password;
    this.salt = this.makeSalt();
    this.hashed_password = this.encryptPassword(password);
    console.log('virtual password 호출됨 : ' + this.hashed_password);
	})
    .get(function(){return this._password});

// 비밀번호 암호화 메소드
UserSchema.method('encryptPassword', function(plainText, inSalt){
    if(inSalt){
        return crypto.createHmac('sha1', inSalt).update(plainText).digest('hex');
    } else{
        return crypto.createHmac('sha1', this.salt).update(plainText).digest('hex');
    }
});

// salt 값 만들기 메소드
UserSchema.method('makeSalt', function(){
    return Math.round((new Date().valueOf() * Math.random())) + '';
});

// 인증 메소드 - 입력된 비밀번호와 비교 (true/false 리턴)
UserSchema.method('authenticate', function(plainText, inSalt, hashed_password){
    if(inSalt){
        console.log('authenticate 호출됨 : %s -> %s : %s', plainText,
                    this.encryptPassword(plainText, inSalt), hashed_password);
        return this.encryptPassword(plainText, inSalt) === hashed_password;
    } else{
        console.log('authenticate 호출됨 : %s -> %s : %s', plainText,
                    this.encryptPassword(plainText), hashed_password);
        return this.encryptPassword(plainText) == hashed_password;
    }
});

 

'Do it! Node.js 프로그래밍'을 공부한 내용입니다.

댓글