Bcrypt 암호화 쉽게 이해하고 사용하기

Bcrypt란?

비크립트(Bcrypt)는 암호화 방식의 한 종류로 굉장히 흔하게 사용되는 방법 중 하나입니다. 암호화 방식으로 해시 함수 방식을 사용합니다. 해시 함수는 임의의 크기의 데이터를 고정된 크기의 값으로 매핑하는 함수입니다. 간단하게 설명해보겠습니다. 해시 함수는 input값이 들어오면, 이를 고정된 크기의 유일무이한 output값으로 변환해준다고 생각하면 이해하기 쉽습니다. 또한 이 과정에서 output값을 다시 input값으로 원상복구시키는 것이 굉장히 어렵도록 설계됩니다.

또한 Bcrypt는 이런 해시 함수 방식에 salt(솔트)라는 개념을 추가한 방식입니다.

해시 함수

먼저 해시 함수의 대표적인 SHA-256에 대해 알아보겠습니다.

SHA-256

해시 함수에서 가장 대표적인 것이 SHA-256입니다. SHA-256의 특징은 다음과 같습니다.

  1. 고정된 출력 크기: 해시 함수는 입력으로부터 고정된 크기의 출력 값을 생성합니다. 예를 들어, SHA-256 해시 함수는 항상 256비트의 출력 값을 생성합니다.
  2. 단방향성(One-wayness): 해시 함수는 입력 값을 해시 값으로 쉽게 변환할 수 있지만, 해시 값으로부터 원래 입력 값을 복원하는 것은 매우 어렵거나 불가능합니다. 즉, 주어진 해시 값으로는 원래 입력 값을 알아내기가 어렵습니다.
  3. 충돌 저항성(Collision resistance): 충돌은 두 개 이상의 서로 다른 입력 값이 같은 해시 값을 생성하는 경우를 말합니다. 해시 함수는 가능한 모든 입력에 대해 유일한 해시 값을 생성하려고 노력합니다. 좋은 해시 함수는 충돌이 발생할 확률이 매우 낮습니다.
  4. 안전성(Security): 해시 함수는 입력 값의 작은 변화에도 완전히 다른 출력 값을 생성하여 보안성을 유지해야 합니다. 이것은 해시 함수가 입력 데이터의 작은 수정을 감지하는 데 유용하게 사용됩니다.

Bcrpyt에서 추가된 salt란?

Bcrypt에서 추가된 솔트라는 개념은 레인보우 테이블(rainbow table)을 방지하기 위한 장치입니다.

레인보우 테이블(rainbow table)이란?

레인보우 테이블은 해시 함수의 취약성을 노리고 제작되는 큰 규모의 데이터베이스 테이블을 의미합니다.

레인보우 테이블을 이용해 비밀번호를 탈취하는 과정은 다음과 같습니다. 먼저 특정 어플리케이션에서 사용되는 비밀번호 암호화용 해시 함수를 알아냈다고 가정합니다. 그러면 이 해시 함수를 이용해 다량의 input데이터와 해당 input데이터를 해시 함수로 해시화했을 때 나오는 output데이터를 한 행에 넣어 데이터베이스에 저장합니다.

그러면 데이터베이스에 해시화된 비밀번호를 탈취했을 때, 해당 값이 output데이터로 있는 행을 조회한 후 그 행의 input 데이터를 탈취하면 본래 비밀번호를 탈취할 수 있습니다.

솔트(Salt)란?

솔트는 이런 레인보우 테이블을 방지하기 위해 사용됩니다. 간단하게 설명하자면 해시 함수를 적용하기 전에 항상 랜덤하게 바뀌는 약간의 잡음을 더해 한 번 더 꼬아주는 암호화 방식입니다.

예를 들어, 해시 함수를 사용하는 과정에 솔트를 사용하지 않으면 동일한 input에는 동일한 output이 생성됩니다. 1을 해시 함수에 넣으면 2가 나온다고 가정합시다. 그럼 해시화된 값을 탈취했을 때 이 값이 2라면 기존 비밀번호가 1임을 바로 알 수 있습니다.

하지만 솔트를 사용한다면 항상 다른 솔트값이 적용되므로 다른 값이 나옵니다. 예를 들면 1에 +1이라는 솔트를 뿌리고 해시 함수에 넣으면 5가 나오고, 다음에도 동일하게 1을 넣었을 때는 +2라는 솔트를 뿌리고 해시 함수에 넣으면 13이 나온다고 가정합시다. 그러면 5와 13이라는 값을 탈취했다고 가정했을 때 이 값이 동일한 비밀번호 1로부터 해시화된 값임을 알기가 어려워집니다.

여기서 약간 의아(?)한 점은 솔트도 해시화된 값에 제공된다는 것입니다. 간단하게 설명하자면 해시화된 값 5와 13에 5(+1), 13(+2) 이런 느낌으로 어떤 솔트가 적용되었는지 알려준다는 것입니다. 저는 개인적으로 이런 과정이 비밀번호 탈취자들이 해시 함수를 역으로 추적하는데 도움을 주는 것은 아닐까 걱정했지만 해당 정보를 알아도 해시 함수를 역으로 진행하여 복호화하는 것은 힘들다고 합니다. 이렇게 어떤 솔트를 사용했는지 알려주는 이유는 인증을 위해서입니다. 만약 어떤 솔트를 사용했는지 아예 알려주지 않는다면 비밀번호의 주인이 로그인을 시도하려 했을 때 조차도 인증을 진행할 수 없는 상황이 발생합니다. 비밀번호에 어떤 솔트값을 뿌린 후 해시 함수에 넣는다면 이 값은 솔트값에 따라 항상 바뀌기 때문에 처음에 회원가입 당시 사용한 솔트값을 동일하게 사용하지 않는다면 데이터베이스에 저장된 해시화된 비밀번호와 일치하지 않게됩니다.

Bcrpyt 암호 구조

$2b$10$BWOUQsDSs9mzQOWtQKuR/u7PcZXAUtBKkgpvB.rksPR5a38uR/cce

Bcrpyt를 이용해 비밀번호를 암호화하면 위와 같은 값을 얻을 수 있습니다. 이 값에는 다양한 정보가 포함되어 있습니다.

  • bcrypt 알고리즘 버전 암호화하는 알고리즘 버전을 의미
  • 솔트 라운드 수 암호화 계산 횟수. 즉, 얼마나 복잡하게 계산할지 정하는 부분. 디폴트로 10 지정된 경우가 많음
  • 솔트값 암호화하기 전 비밀번호에 더할 값
  • 해시값 ‘비밀번호 + 솔트’를 솔트 라운드 수 만큼 bcrypt 알고리즘을 이용해 암호화한 값

이때 각 부분은 $ 표시로 경계를 짓습니다. 위의 예시의 경우는 다음과 같습니다.

$2b  --> bcrypt 알고리즘 버전
$10  --> 솔트 라운드 수
$BWOUQsDSs9mzQOWtQKuR/u7PcZXAUtBKkgpvB.rksPR5a38uR/cce --> 솔트값, 해시값 이어 붙인 것

이를 통해 두 명의 사용자를 만들고 두 명 모두 비밀번호를 1234로 설정해봅니다. 그러면 같은 비밀번호를 사용했음에도 다른 솔트값, 해시값을 반환하는 모습을 확인할 수 있습니다.

결과적으로 동일한 비밀번호를 사용해도 다른 암호화된 값(솔트값, 해시값 조합)을 반환해 보안을 강화할 수 있고, 역으로 복호화 또한 불가능하여 오로지 원래 비밀번호를 아는 사람만이 인증 과정을 통과할 수 있게 할 수 있습니다.

results matching ""

    No results matching ""