본문 바로가기

Node.js/NPM

bcrypt의 작동원리와 노드에서 사용하는 방법

1. 간단한 원리

 

bcrypt를 사용하면 매번 솔트가 달라지기 때문에 

해시 역시도 달라지고 데이터베이스에 특정한 해시를 저장하더라도 보안에 문제가 되지 않는다.

해시가 그때그때마다 달라져 해시를 이용해 비밀번호를 찾아내기 어렵기 때문이다.

 

그럼 데이터베이스의 해시가 달라지는데 어떻게 비밀번호가 일치하는지 확인할 수 있을까?

bcrypt는 단순히 사용자가 입력한 비밀번호를 해싱해

데이터베이스에 저장된 해시와 비교하는 방식으로 돌아가지 않는다.

 

대신 사용자가 입력한 비밀번호와 데이터베이스에 저장된 해시 둘에,

어떤 해싱(로직?)을 적용해서 비교한다고 한다.

이것이 가능한 이유는 저장된 해시 앞부분에 솔트 정보가 들어 있고 

이를 추론해서 사용자가 입력한 비밀번호의 해시와 비교할 수 있기 때문인 것 같다.

(자세한 내용은 아래 링크를 참고 바란다.)

 

 

2. 노드에서 사용하는 방법

 

// bcrypt 모듈을 불러온다.

const bcrypt = require('bcrypt');

 

// 데이터베이스에 비밀번호를 저장할 때

const salt = await bcrypt.genSalt(10); // 기본이 10번이고 숫자가 올라갈수록 연산 시간과 보안이 높아진다.

const hashed = await bcrypt.hash('12345678', salt); // hashed를 데이터베이스에 저장한다.

 

salt와 hashed의 값은 아래처럼 실행할 때마다 달라진다.

 

// 1번째 실행 때 로그

salt :  $2b$10$6JJhj239ykjB.TVOIj8E/.
hashed :  $2b$10$6JJhj239ykjB.TVOIj8E/.mg7ytYatwdC39nd2X0wx8vyBB8M54TO

 

// 2번째 실행 때 로그

salt :  $2b$10$PeBWt1vUItW.AJ.wCkvpMe

hashed :  $2b$10$PeBWt1vUItW.AJ.wCkvpMeD2RQIxEben7JsBMomeG/lzoE5hPd6xG

 

// 3번째 실행 때 로그

salt :  $2b$10$AHuiruyCUusfsxaSmN1obe

hashed :  $2b$10$AHuiruyCUusfsxaSmN1obevX2pa/z6xIR5D6U6LFoF8DwZLtr7WDK

 

hash에 salt도 저장되는 것을 볼 수 있다.

정확히 어떤 로직을 쓰는지는 모르지만 후에 이 salt를 이용해서

사용자가 로그인으로 요청한 비밀번호와 데이터베이스에 저장된 비밀번호를 비교할 수 있는 것이다.

 

비밀번호를 확인하려면 아래처럼 compare 메소드를 써서 비교하고

validPassword가 true인 경우에만 로그인을 허가해준다.

 

// 비밀번호를 확인할 때

const validPassword = await bcrypt.compare(req.body.password, user.password);

if (!validPassword) {

    return res.status(400).send('이메일이나 비밀번호가 올바르지 않습니다.');

}

 

참고 : 

When a user logs into our system, we need to check that the password entered is correct. Unlike other systems that would decrypt the password in the database (if it is encrypted), and compare it with the one entered by the user, what I do with bcrypt ( given it implements one-way hashing) is encrypt the one entered by the user. To do this, I will pass the password to bcrypt to calculate the hash, but also the password stored in the database associated with the user (hash). This is because, as mentioned before, the bcrypt algorithm used a random segment (salt) to generate the hash associated with the pasword. This was stored along with the password, and you need it to recalculate the hash of the password entered by the user and finally compare with the one entered when registering and see if they match.

https://medium.com/javascript-in-plain-english/how-bcryptjs-works-90ef4cb85bf4

 

And, effectively, res is false. We did not store the salt though, so how does bcrypt.compare know which salt to use? Looking at a previous hash/salt result, notice how the hash is the salt with the hash appended to it:

bcrypt.compare deduces the salt from the hash and is able to then hash the provided password correctly for comparison.

https://auth0.com/blog/hashing-in-action-understanding-bcrypt/