레인보우 테이블을 사용한 공격 방지를 위해 솔트(salt)를 통합한 해시함수
레인보우 테이블 : password와 digest가 mapping된 table
Digest : 해시함수에 의해 password가 암호화된 데이터
Bcrypt이전에는 사용자의 민감한 데이터를 저장하기 위해서 일반적인 단방향 암호화 해시함수를 사용했다.
password를 해시함수에 대입하면, Digest가 출력되고, Digest를 서버에 저장하는식으로 말이다.
그러나, 위의 방식에는 다음과 같은 문제점이 존재한다.
MD-5 , SHA - 1 , SHA - 2와 같은 해시함수들은 레인보우 테이블이 존재하기 때문에, 해커들이 서버에 저장된 digest를 탈취하여 레인보우 테이블과 대조해볼 경우, 사용자의 password가 유출될 수 있다.
해시함수의 실행속도가 빠를 경우에 문제가 된다. 해시함수의 실행속도가 빠르다는 것은 반대로 말하면, 해커들이 짧은 시간안에 많은 password를 해시함수에 돌려볼 수 있다는 것이다. 즉, 서버에 저장된 digest를 출력하게하는 password를 찾을 가능성이 높아진다는 뜻이다.
위의 문제점들은 다음과 같은 방식으로 해결할 수 있다.
해시함수를 돌리기 전에 password에 임의의 문자열을 덧붙이는 것이다. 사용자마다 고유한 salt를 password 뒤에 이어붙여서 해시함수를 돌린다면, 같은 password를 사용하는 사용자들이 있을지라도 digest가 모두 달라지게된다. 즉, 레인보우 테이블의 유용성이 떨어지게된다.
password를 해시함수에 돌려서 나온 digest를 다시 해시함수에 넣는 과정을 반복할 경우에, 해시함수의 실행시간이 길어지게된다. 즉 해커들이 brute force방법을 사용할 경우, 소요시간을 늘림으로써 password를 찾을 가능성을 낮춘다.
Bcrypt는 1번 해결책과 2번해결책이 모두 적용된 해시함수라고 할 수 있다.
1234를 Bcrypt를 통해 암호화 할 경우
$2a$12$enav44jvS6nF0BqQUch9wuE/YhvDRwLPQJo5Z4LW6Nphd3ygK47.S
라는 결과값이 나온다.
$2a$12$enav44jvS6nF0BqQUch9wu 는 salt 값이고,
뒷부분은 password + salt를 해시화 한 값이다.
salt값에는 다음과 같은 정보가 포함되어있다.
$2a는 Bcrypt의 Version 정보를 가지고 있다. (추가적으로 $2b , $2y등의 버전이 있다.)
$12는 key stretching 횟수에 관한 정보를 가지고 있다. (12는 2의 12승 번 해시함수를 돌렸다는 의미이다.)
$enav44jvS6nF0BqQUch9wu는 사용자마다 고유한 salt로 real_salt라고 불린다.
즉, bcrypt의 digest의 앞부분에는 salt에 관한 정보가 담겨있다.
임의의 password와 digest를 대조하는 경우에는
digest에서 real_salt값을 얻어낸 뒤에, 임의의 password + real_salt 값을 salt에 포함된 정보를 이용해서 해시화 한뒤, digest의 뒷부분과 비교하면 된다.
출처