[security] bcrypt는 어떻게 내장 소금을 가질 수 있습니까?

Coda Hale의 기사 “암호를 안전하게 저장하는 방법” 은 다음과 같이 주장합니다.

bcrypt에는 레인보우 테이블 공격을 방지하기 위해 소금이 내장되어 있습니다.

그는 이 논문을 인용하며 , 이는 OpenBSD의 구현에서 bcrypt다음 과 같이 말합니다 :

OpenBSD는 arcfour (arc4random (3)) 키 스트림에서 128 비트 bcrypt salt를 생성하며 커널은 장치 타이밍에서 수집 한 임의의 데이터를 시드합니다.

이것이 어떻게 작동하는지 이해하지 못합니다. 소금에 대한 나의 개념에서 :

  • 저장된 비밀번호마다 달라야하므로 별도의 레인보우 테이블을 생성해야합니다.
  • 반복 가능하도록 어딘가에 저장해야합니다. 사용자가 로그인을 시도 할 때 비밀번호를 입력하고, 비밀번호를 처음 저장할 때와 동일한 소금 및 해시 절차를 반복하고 비교합니다.

bcrypt와 함께 Devise (Rails 로그인 관리자)를 사용할 때 데이터베이스에 솔트 열이 없으므로 혼란 스럽습니다. 소금이 무작위이며 어디에도 저장되지 않은 경우 어떻게 해싱 프로세스를 안정적으로 반복 할 수 있습니까?

간단히 말해서, bcrypt는 어떻게 내장 소금을 가질 수 있습니까?



답변

이것은 bcrypt입니다.

임의의 소금을 생성하십시오. “비용”요소가 사전 구성되었습니다. 비밀번호를 수집하십시오.

솔트 및 비용 요소를 사용하여 비밀번호에서 암호화 키를 파생하십시오. 잘 알려진 문자열을 암호화하는 데 사용하십시오. 비용, 소금 및 암호문을 저장 하십시오 . 이 세 가지 요소의 길이는 알려진 것이기 때문에 하나의 필드에 연결하여 저장하기는 쉽지만 나중에 분리 할 수 ​​있습니다.

누군가 인증을 시도하면 저장된 비용과 소금을 검색하십시오. 입력 암호, 비용 및 소금에서 키를 파생하십시오. 잘 알려진 동일한 문자열을 암호화하십시오. 생성 된 암호문이 저장된 암호문과 일치하면 암호가 일치합니다.

Bcrypt는 PBKDF2와 같은 알고리즘을 기반으로하는 기존 방식과 매우 유사한 방식으로 작동합니다. 주요 차이점은 알려진 일반 텍스트를 암호화하기 위해 파생 키를 사용한다는 것입니다. 다른 체계는 (합리적으로) 키 파생 함수가 돌이킬 수 없다고 가정하고 파생 키를 직접 저장합니다.


데이터베이스에 저장된 bcrypt“해시”는 다음과 같습니다.

$ 2a $ 10 $ vI8aWBnW3fID.ZQ4 / zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

이것은 실제로 “$”로 구분 된 세 개의 필드입니다.

  • 2a사용 된 bcrypt알고리즘 버전을 식별합니다 .
  • 10비용 요소입니다. 2 키 파생 함수의 10 반복이 사용됩니다 (그런데 충분하지 않습니다. 12 이상의 비용을 권장합니다).
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa소금과 암호문은 수정 된 Base-64에 연결되고 인코딩됩니다. 처음 22자는 솔트의 16 바이트 값으로 디코딩됩니다. 나머지 문자는 인증을 위해 비교할 암호문입니다.

이 예제는 Coda Hale의 루비 구현 문서 에서 발췌 한 것입니다.


답변

나는 그 문구가 다음과 같이 표현되어야한다고 믿는다.

bcrypt에는 레인보우 테이블 공격을 방지하기 위해 생성 된 해시 에 소금이 내장되어 있습니다.

bcrypt유틸리티 자체는 소금의 목록을 유지하기 위해 표시되지 않습니다. 오히려 솔트는 무작위로 생성되고 함수의 출력에 추가되어 나중에 자바 구현에bcrypt 따라 기억됩니다 . 다시 말해, “해시” 는 해시 만이bcrypt 아닙니다 . 오히려 그것은 해시 소금이 연결되어 있습니다.


답변

더 명확하게하기 위해

등록 / 로그인 방향->

비밀번호 + 솔트는 비용, 솔트 및 비밀번호에서 생성 된 키로 암호화됩니다. 우리는 그 암호화 된 값을 호출합니다 cipher text. 그런 다음 소금을이 값에 연결하고 base64를 사용하여 인코딩합니다. 그것에 비용을 첨부하면 다음에서 생성 된 문자열입니다 bcrypt.

$2a$COST$BASE64

이 값은 결국 저장됩니다.

침입자가 암호를 찾으려면 어떻게해야합니까? (다른 방향 <-)

공격자가 DB를 제어 할 수있는 경우 공격자는 쉽게 base64 값을 해독 한 다음 소금을 볼 수 있습니다. 소금은 비밀이 아닙니다. 비록 무작위입니다. 그런 다음 그는 암호를 해독해야합니다 cipher text.

더 중요한 것은 :이 프로세스에는 해시가 없으며 CPU 비용이 많이 드는 암호화-암호 해독이 있습니다. 따라서 무지개 테이블은 여기서 덜 관련이 있습니다.


답변

Spring Security의 PasswordEncoder 인터페이스 문서에서 가져온 것입니다.

 * @param rawPassword the raw password to encode and match
 * @param encodedPassword the encoded password from storage to compare with
 * @return true if the raw password, after encoding, matches the encoded password from
 * storage
 */
boolean matches(CharSequence rawPassword, String encodedPassword);

즉, 다음 로그인시 사용자가 다시 입력 할 rawPassword와 일치해야하며 이전 로그인 / 등록 중에 데이터베이스에 저장되는 Bcrypt 인코딩 비밀번호와 일치해야합니다.


답변