client의 아이디와 비밀번호를 DB에 저장 할 때,
보안을 위해 비밀번호는 암호화 해서 저장할 필요가 있다.
이때 사용하는 해시알고리즘 방법이 bcrypt이다.
npm i bcrypt
bcrypt를 사용해보면서
평문은 같은 값이지만 겉보기엔 전부 서로 다른 해시값들을
bcrypt.compare 를 이용해서 비교해보면 전부 true가 반환되니 신기했다.
import bcrypt from "bcrypt";
const saltRounds = 12;
const password = "1234";
// 암호화
const hashed = bcrypt.hashSync(password, saltRounds);
console.log(hashed);
console.log(bcrypt.compareSync(password, hashed)); // true
// password:1234, saltRounds:12로, 이전에 만든 hashed들
const h1 = "$2b$12$dbnukD8xfEU37zGzPFjGgOGkw5d0EMmlhAZm8bBRmJhdbElbNpHse";
const h2 = "$2b$12$Rw4pmHBD.ood7Fp4PVZWhOmf7YFOq66DeRVhBFeOER0eVhK53xRb.";
const h3 = "$2b$12$mCxMAQOKknkraedEXrSVBeTpstFNQGWSi5TLYxRAMx6TbNgIkyRge";
const h4 = "$2b$12$JTZUbIY//X7ltyQktEpb4.2GrG4YJE/c.pQ.QMDhv3eGCB.c71.m2";
console.log(bcrypt.compareSync(password, h1)); // true
console.log(bcrypt.compareSync(password, h2)); // true
console.log(bcrypt.compareSync(password, h3)); // true
console.log(bcrypt.compareSync(password, h4)); // true
"해시 할때마다 해시된 값이 다른데 어떻게 비밀번호를 비교할 수 있을까?"
bcrypt로 만든 해시값을 가져왔다.
$2b$12$dbnukD8xfEU37zGzPFjGgOGkw5d0EMmlhAZm8bBRmJhdbElbNpHse
각 문자들은 의미가 있는데,
$2b: bcrypt 알고리즘
$12: 2^12번 salt쳐서 hashing 반복
$dbnukD8xfEU37zGzPFjGgO: salt값
Gkw5d0EMmlhAZm8bBRmJhdbElbNpHse: plain password를 위 방법으로 hash한 결과값
즉, 해당 해시값이 어떤 salt를 사용했고, 몇번 반복했는지 포함되어 있으므로,
compare함수는 이 salt와 반복횟수를 이용해 plain password를 bcrypt 알고리즘으로 hash한 값을
DB에 저장된 해시값과 같은지 비교하는 것이다.
+
긴 salt가 추가되고,
hash하는 횟수(cost)도 많아지면 (Key Stretching)
brute-force 공격을 이용한 레인보우 테이블을 만들기가 아주 힘들다고 한다.