똑같은 삽질은 2번 하지 말자

(Node.js) password 암호화 모듈 Crypto(crypto.js에 대해) 본문

Node

(Node.js) password 암호화 모듈 Crypto(crypto.js에 대해)

곽빵 2019. 11. 1. 16:55

Cipher : 일반적인 암호화로 평문 -> 암호문 -> 복호문(평문)의 방식으로 암호화하고 복호화 합니다.

             즉, 암호화를 하기 위한 Key 를 가지고 암호화하며, 복호화합니다.

 

Hmac: 암호화를 하면 다시 되돌릴 수 없기 때문에, 암호화 된 암호문 그 자체를 이용합니다. 흔히

      웹사이트 가입하면 운영자도 가입정보를 알 수 없다고 하는건 이렇게 Hmac으로 암호화되어서 입니다.

 

Module 가져 온뒤, 사용해보겠습니다.

 

1.Cipher 방식을 이용한 암호화

var crypto = require('crypto');

// 암호화
var cipher = crypto.createCipher('aes256','password'); 
// aes256 방식으로 password(key)로 암호화하겠다.
cipher.update('TestCipher','ascii','hex');
// update('평문(암호화이전의글)','input type','output type');
var cipherd = cipher.final('hex');
// 암호문

//복호화
var decipher = crypto.createDecipher('aes256','password');
decipher.update(cipherd,'hex','ascii');
var decipherd = decipher.final('ascii');
// 암호화 방법의 parameter 방식은 동일함




 

 

2.Hmac 방식을 이용한 암호화

 

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) {
        // plainText가 사용자가 입력한 password이고 hashed_password가 암호화되서 저장된 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), this.hashed_password);
            return this.encryptPassword(plainText) === this.hashed_password;
        }
    });

virtual 을 이용해서 Hmac 암호화 방식을 사용해 보았습니다.

virtual 은 MongoDB에 저장되지 않는 속성이므로 편하게 set get을 설정 편의를 위해서 사용하는 것 같습니다.

(사실 왜 쓰는지는 모르겠지만, 개인적인 생각으로는 좀더 유연한 Schema가 되기위한 기능이라고 생각합니다..

정해진 컬렉션 속성들로 여러가지 정보를 추출 비교 하기 위해 만들어진..?)

 

실제로 passport 인증 모듈에서 password 인증할 때 사용해 보았습니다.

 

module.exports = new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true // 이 옵션을 설정하면 아래 콜백 함수의 첫번째로 req 전달
}, function (req, email, password, done) {
    console.log('passport의 local-login 호출됨 : ' + email + ', ' + password);

    var database = req.app.get('database');
    database.UserModel.findOne({
        'email': email
    }, function (err, user) {
        console.log('-----------------로그인----------------- ');
        console.dir(user);// 해당 model 정보 출력
        if (err) {
            return done(err);
        }

        // 등록된 사용자가 없는경우
        if (!user) {
            console.log('계정이 일치하지 않음.');
            return done(null, false, req.flash('loginMessage', '등록된 계정이 없습니다.'));
            // 인증 실패 처리
        }
        // 비밀번호 비교하여 맞지 않는 경우
        var authenticated =
            user.authenticate(password, user._doc.salt, user._doc.hashed_password);
        if (!authenticated) {
            console.log('비밀번호 일치하지 않음');
            return done(null, false, req.flash('loginMessage', '비밀번호가 일치하지 않음'));
        }
        console.log('계정과 비밀번호가 일치함.');
        return done(null, user);
        // 인증 성공 처리 serializeUser에 user 정보 전달
    })
});

 

Comments