사용자의 패스워드와 같은 민감한 정보는 개발자 본인도 알아볼 수 없도록 암호화하여 데이터베이스에 저장해야한다.
어떻게 암호화를 할 수 있을까?
bcrypt라는 npm 모듈을 사용하여 패스워드를 해싱할 수 있다.
위키피디아에서 정의한 bcrypt는 아래와 같다.
bcrypt is a password-hashing function designed by Niels Provos and David Mazières, based on the Blowfish cipher and presented at USENIX in 1999.[1] Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.
위에서 보다시피 bcrypt는 Niels Provos와 David Mazières에 의해 디자인된 password-hashing function이며 이 bcrypt는 1999년 USENIX (어딘진 모름)에서 발표된 Blowfish라는 암호를 기반으로 만들어졌다고 한다.
(이게 어떤 공격인진 잘 모르겠으나) rainbow table 어택에 대항하기 위해 salt를 추가했을 뿐 아니라 bcrypt는 적응형 function이다.(적응형 함수는 또 뭘까?)
: (어쨌든!) 시간이 지남에 따라, 반복 횟수를 늘려 속도를 늦출 수 있으므로 계산 성능이 향상되더라도 무차별적인 검색 공격에 대한 내성을 유지할 수 있다고 한다.
※ rainbow table 공격 : A rainbow table is a precomputed table for caching the output of cryptographic hash functions, usually for cracking password hashes.
-> 지금까지 알아본 정의에 의하면 bcrypt는 무차별적으로 패스워드를 때려맞추려는 공격이 들어와도 알아내기까지의 시간을 늦출 수 있어서 rainbow table 공격에 대항할 수 있는 password-hashing-function이라고 한다.
Description
bcrypt function의 input으로는 password string과 숫자로된 cost, 16byte의 salt가 들어간다.
salt는 일반적으론 랜덤값이다.
bcrypt는 이러한 input값들을 24byte의 해쉬값으로 계산하기 위해 사용한다.
bcrypt function의 최종 output의 형태는 아래 형식의 string이다.
$2<a/b/x/y>$[cost]$[22 character salt][31 character hash]
예를 들어, password abc123xyz
, cost 12
, 그리고 랜덤한 salt
를 갖는 bcrypt의 output은 아래와 같다.
$2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
\__/\/ \____________________/\_____________________________/
Alg Cost Salt Hash
npm i bcrypt
위 npm i를 통해 모듈을 설치했다면 어떻게 사용하는 지 알아보자.
import bcrypt from 'bcrypt';
const saltRounds = 10;
const myPassword = 'abc123xyz';
const otherPassword = 'zcvd1255';
//CASE 1) 패스워드 해싱하여 변수에 할당한다면,
const myHashed = bcrypt.hash(myPassword, saltRounds);
//CASE 2) 패스워드 해싱하여 디비에 저장한다면,
bcrypt.hash(myPassword,saltRounds, function(err,hash) {
// DB에 hash 저장하는 로직 작성..
});
//패스워드를 확인한다면,
/*
CASE 3)
@myPassword : 로그인 요청시 올바른 패스워드를 넘겼다고 가정
@hash : DB에 저장된 hash값
@callback : 앞의 인자 둘을 비교했을 때의 결과를 리턴 -> 이 경우, true
*/
bcrypt.compare(myPassword, hash, function(err,result) {
// result == true
});
/*
CASE 4)
@myPassword : 로그인 요청시 틀린 패스워드를 넘겼다고 가정
@hash : DB에 저장된 hash값
@callback : 앞의 인자 둘을 비교했을 때의 결과를 리턴 -> 이 경우, false
*/
bcrypt.compare(otherPassword, hash, function(err, result) {
// result == false
});
bcrypt를 사용하는 방식은 promise나 async/await을 활용해 비동기적으로 할 수도 있으니 자세한 사용법은 아래의 링크를 참고하자.
참고
https://www.npmjs.com/package/bcrypt
https://en.wikipedia.org/wiki/Bcrypt