Blowfish로 긴 암호 (> 72 자)를 해시하는 방법


91

지난주에 암호 해싱에 대한 많은 기사를 읽었으며 Blowfish는 현재 최고의 해싱 알고리즘 중 하나 인 것 같습니다.하지만이 질문의 주제는 아닙니다!

72 자 제한

Blowfish는 입력 한 비밀번호의 처음 72 자만 고려합니다.

<?php
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$hash = password_hash($password, PASSWORD_BCRYPT);
var_dump($password);

$input = substr($password, 0, 72);
var_dump($input);

var_dump(password_verify($input, $hash));
?>

출력은 다음과 같습니다.

string(119) "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)"
string(72) "Wow. This is a super secret and super, super long password. Let's add so"
bool(true)

보시다시피 처음 72 자만 중요합니다. Twitter는 bcrypt로 알려진 blowfish를 사용하여 암호 ( https://shouldichangemypassword.com/twitter-hacked.php ) 를 저장 하고 추측합니다. Twitter 암호를 72 자 이상의 긴 암호로 변경하면 다음 방법으로 계정에 로그인 할 수 있습니다. 처음 72 자만 입력합니다.

복어와 후추

"페퍼 링"암호에 대해 많은 의견이 있습니다. 어떤 사람들은 이것이 필요하지 않다고 말합니다. 왜냐하면 당신은 비밀 후추 문자열이 해시를 향상시키지 못하도록 알려진 / 게시 된 것이라고 가정해야하기 때문입니다. 나는 별도의 데이터베이스 서버를 가지고 있으므로 데이터베이스 만 유출되고 지속적인 후추가 발생하지 않을 가능성이 높습니다.

이 경우 (후추가 유출되지 않음) 사전에 기반한 공격을 더 어렵게 만듭니다 (맞지 않으면 수정). 후추 끈도 유출 된 경우 : 그렇게 나쁘지는 않습니다. 여전히 소금이 있고 후추가없는 해시만큼 잘 보호됩니다.

그래서 비밀번호를 입력하는 것은 적어도 나쁜 선택이 아니라고 생각합니다.

암시

72 자 (및 후추)가 넘는 암호에 대해 Blowfish 해시를 얻으라는 제안은 다음과 같습니다.

<?php
$pepper = "foIwUVmkKGrGucNJMOkxkvcQ79iPNzP5OKlbIdGPCMTjJcDYnR";

// Generate Hash
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$password_peppered = hash_hmac('sha256', $password, $pepper);
$hash = password_hash($password_peppered, PASSWORD_BCRYPT);

// Check
$input = substr($password, 0, 72);
$input_peppered = hash_hmac('sha256', $input, $pepper);

var_dump(password_verify($input_peppered, $hash));
?>

이것은 이 질문을 기반으로 합니다 : password_verifyreturn false.

질문

더 안전한 방법은 무엇입니까? 먼저 SHA-256 해시 (64 자 반환)를 얻거나 암호의 처음 72 자만 고려합니까?

장점

  • 사용자는 처음 72 자만 입력하여 로그인 할 수 없습니다.
  • 문자 제한을 초과하지 않고 고추를 추가 할 수 있습니다.
  • hash_hmac의 출력은 아마도 암호 자체보다 더 많은 엔트로피를 가질 것입니다.
  • 암호는 두 가지 다른 기능에 의해 해시됩니다.

단점

  • 복어 해시를 만드는 데는 64 자만 사용됩니다.


편집 1 : 이 질문은 blowfish / bcrypt의 PHP 통합만을 다룹니다. 의견 주셔서 감사합니다!


3
Blowfish는 암호를 자르는 유일한 방법이 아니며 사람들이 실제보다 더 안전하다고 오해하게 만듭니다. 8 자 제한에
DOK

2
72 자 잘림이 Blowfish 알고리즘의 기본입니까 아니면 PHP 구현입니까? IIRC Blowfish는 사용자 암호를 암호화하기 위해 (적어도 일부) 'nix'에서도 사용됩니다.
Douglas B. Staple 2013 년

3
문제는 Blowfish가 아니라 Bcrypt에 있습니다. 이 문제는 Python과 Bcrypt만으로 재현 할 수 있습니다.
Blender

@Blender : 귀하의 의견과 작업에 감사드립니다. 나는 복어와 bcrypt에 대한 PHP에서 다른 기능을 찾을 수 없었지만 동일하지만. 그러나 그것은 PHP에서 나에게 어떤 차이를 만들지 않습니까? 표준 PHP 기능을 사용하고 싶습니다.
Frederik Kammer 2013 년

1
Openwall의 PHP 비밀번호 해싱 프레임 워크 (PHPass) 도 참조하세요 . 사용자 암호에 대한 여러 일반적인 공격에 대해 휴대 가능하고 강화되었습니다. 프레임 워크 (SolarDesigner)를 작성한 사람은 John The Ripper 를 작성 하고 Password Hashing Competition 에서 심사 위원으로 참여한 사람입니다 . 그래서 그는 암호 공격에 대해 한두 가지를 알고 있습니다.
jww

답변:


135

여기서 문제는 기본적으로 엔트로피 문제입니다. 이제부터 살펴 보겠습니다.

문자 당 엔트로피

바이트 당 엔트로피 비트 수는 다음과 같습니다.

  • 16 진수 문자
    • 비트 : 4
    • 값 : 16
    • 72 자 엔트로피 : 288 비트
  • 영숫자
    • 비트 : 6
    • 값 : 62
    • 72 자 엔트로피 : 432 비트
  • "공통"기호
    • 비트 : 6.5
    • 값 : 94
    • 72 자 엔트로피 : 468 비트
  • 전체 바이트
    • 비트 : 8
    • 값 : 255
    • 72 자 엔트로피 : 576 비트

따라서 우리가 행동하는 방식은 우리가 기대하는 캐릭터 유형에 따라 다릅니다.

첫 번째 문제

코드의 첫 번째 문제는 "pepper" 해시 단계가 16 진수 문자를 출력한다는 것입니다 (네 번째 매개 변수가hash_hmac() 가 설정되지 않았기 때문에).

따라서 후추를 해싱하면 암호에 사용할 수있는 최대 엔트로피를 2 배 ( 가능한 576에서 288로) 효과적으로 줄일 수 있습니다. 비트).

두 번째 문제

그러나 처음 sha256에는 256약간의 엔트로피 만 제공합니다 . 따라서 가능한 576 비트를 256 비트로 효과적으로 줄일 수 있습니다. 정의상 해시 단계 * 즉시 * 는 암호에서 가능한 엔트로피 의 50 % 이상을습니다 .

SHA512사용 가능한 엔트로피를 약 12 ​​% 만 줄일 수있는 로 전환하여이 문제를 부분적으로 해결할 수 있습니다. 그러나 그것은 여전히 ​​중요하지 않은 차이입니다. 이 12 %는 순열 수를 1.8e19. 그것은 큰 숫자입니다. 그리고 그것이 그것을 줄이는 요인입니다 ...

근본적인 문제

근본적인 문제는 72자를 초과하는 세 가지 유형의 암호가 있다는 것입니다. 이 스타일 시스템이 그들에게 미치는 영향은 매우 다를 것입니다.

참고 : 이제부터는 SHA512원시 출력 (16 진수 아님) 을 사용하는 후추 시스템과 비교한다고 가정 합니다.

  • 높은 엔트로피 임의 암호

    이들은 암호에 대해 큰 키를 생성하는 암호 생성기를 사용하는 사용자입니다. 무작위 (인간 선택이 아닌 생성됨)이며 캐릭터 당 엔트로피가 높습니다. 이러한 유형은 상위 바이트 (문자> 127) 및 일부 제어 문자를 사용합니다.

    이 그룹은 해당 해시 함수는 것입니다 크게 가용 엔트로피로 감소 bcrypt.

    다시 말하겠습니다. 높은 엔트로피, 긴 암호를 사용하는 사용자의 경우 솔루션 은 암호의 강도를 측정 가능한 양만큼 크게 줄입니다. (72 자 암호의 경우 62 비트 엔트로피 손실, 긴 암호의 경우 그 이상)

  • 중간 엔트로피 임의 암호

    이 그룹은 공통 기호가 포함 된 비밀번호를 사용하지만 상위 바이트 또는 제어 문자는 사용하지 않습니다. 입력 가능한 암호입니다.

    이 그룹의 경우 약간 더 많은 엔트로피 잠금 해제 (생성하지 않고 bcrypt 암호에 더 많은 엔트로피를 허용). 내가 약간 말할 때 나는 약간을 의미합니다. 손익분기 점은 SHA512에있는 512 비트를 최대로 사용할 때 발생합니다. 따라서 피크는 78 자입니다.

    다시 말하겠습니다. 이 암호 클래스의 경우 엔트로피가 부족해지기 전에 6 자만 추가로 저장할 수 있습니다.

  • 낮은 엔트로피 비 랜덤 암호

    무작위로 생성되지 않은 영숫자 문자를 사용하는 그룹입니다. 성경 인용구와 같은 것. 이 문구는 문자 당 약 2.3 비트의 엔트로피를 가지고 있습니다.

    이 그룹의 경우 해싱을 통해 더 많은 엔트로피를 잠금 해제 할 수 있습니다 (생성하는 것이 아니라 bcrypt 암호 입력에 더 많이 맞출 수 있음). 손익분기 점은 엔트로피가 부족하기 전에 약 223 자입니다.

    다시 말해 봅시다. 이 암호 클래스의 경우 사전 해싱은 확실히 보안을 크게 향상시킵니다.

현실 세계로 돌아 가기

이러한 종류의 엔트로피 계산은 실제 세계에서 그다지 중요하지 않습니다. 중요한 것은 엔트로피를 추측하는 것입니다. 이것이 공격자가 할 수있는 일에 직접적인 영향을 미칩니다. 그것이 당신이 극대화하고 싶은 것입니다.

엔트로피를 추측하는 연구는 거의 없지만 제가 지적하고 싶은 몇 가지 사항이 있습니다.

연속적으로 72 개의 올바른 문자를 무작위로 추측 할 확률은 매우 낮습니다. 이 충돌을 겪는 것보다 파워 볼 복권에 21 번 당첨 될 가능성이 더 큽니다. 그게 우리가 말하는 숫자가 얼마나 큰지입니다.

그러나 우리는 통계적으로 그것을 우연히 발견하지 못할 수도 있습니다. 구문의 경우 처음 72자가 동일 할 확률은 임의의 암호보다 훨씬 높습니다. 그러나 여전히 사소한 수준입니다 (문자 당 2.3 비트를 기준으로 Powerball 복권을 5 번 이길 가능성이 더 높습니다).

거의

실제로는 중요하지 않습니다. 누군가가 처음 72자를 맞히고 후자의 문자가 큰 차이를 만들 가능성이 너무 낮아 걱정할 필요가 없습니다. 왜?

글쎄, 당신이 문구를 취한다고 가정 해 봅시다. 그 사람이 처음 72자를 정확하게 맞출 수 있다면 정말 좋거나 (가능성이 낮음) 일반적인 문구입니다. 일반적인 문구 인 경우 유일한 변수는 제작 시간입니다.

예를 들어 보겠습니다. 성경에서 인용을합시다 (다른 이유가 아니라 긴 텍스트의 일반적인 소스이기 때문에) :

이웃집을 탐 내지 마십시오. 당신은 이웃의 아내 나 그의 하인이나 여종, 그의 소나 당나귀, 또는 이웃에게 속한 것을 탐 내서는 안됩니다.

180 자입니다. 73 번째 문자는 g두 번째 neighbor's. 그렇게 많이 추측했다면에서 멈추지 않고 nei나머지 구절을 계속할 것입니다 (비밀번호가 사용되는 방식이기 때문에). 따라서 "해시"가 많이 추가되지 않았습니다.

BTW : 저는 성경 인용문을 사용하는 것을 절대적으로지지하지 않습니다. 사실 정반대입니다.

결론

먼저 해싱하여 긴 암호를 사용하는 사람들을 많이 돕지는 않을 것입니다. 당신이 확실히 도울 수있는 몇몇 그룹. 일부는 확실히 다칠 수 있습니다.

그러나 결국에는 그 어느 것도 지나치게 중요하지 않습니다. 우리가 다루고있는 숫자는 단지입니다 WAY 너무 높다. 엔트로피의 차이는 크지 않을 것입니다.

bcrypt를 그대로 두는 것이 좋습니다. 방지하려는 공격이 발생하는 것보다 해싱을 망칠 가능성이 더 높습니다 (말 그대로 이미 해봤고 그 실수를 한 첫 번째 또는 마지막이 아닙니다).

나머지 사이트 보안에 집중하십시오. 그리고 등록시 암호 상자에 암호 엔트로피 미터를 추가하여 암호 강도를 표시합니다 (암호가 너무 길어서 사용자가 변경하려는 경우 표시).

그것은 적어도 내 $ 0.02 (또는 $ 0.02 이상)입니다 ...

"비밀"후추를 사용하는 한 :

bcrypt에 하나의 해시 함수를 제공하는 것에 대한 연구는 말 그대로 없습니다. 따라서 "peppered"해시를 bcrypt에 입력하면 알려지지 않은 취약점이 발생하는지 여부는 확실하지 않습니다 ( hash1(hash2($value))충돌 저항 및 사전 이미지 공격과 관련된 심각한 취약점을 노출 할 수 있음을 알고 있습니다).

이미 비밀 키 ( "후추") 저장을 고려하고 있다는 점을 고려할 때 잘 연구되고 이해 된 방식으로 사용하는 것은 어떻습니까? 해시를 저장하기 전에 암호화하지 않는 이유는 무엇입니까?

기본적으로 암호를 해시 한 후 전체 해시 출력을 강력한 암호화 알고리즘에 제공합니다. 그런 다음 암호화 된 결과를 저장하십시오.

이제 SQL-Injection 공격은 암호 키가 없기 때문에 유용한 정보를 유출하지 않습니다. 키가 유출되면 공격자는 일반 해시를 사용하는 것보다 낫지 않습니다 (증명할 수 있지만 후추 "사전 해시"가 제공되지 않는 것).

참고 : 이렇게하려면 라이브러리를 사용하십시오. PHP의 경우 Zend Framework 2의 패키지를 강력히 권장 Zend\Crypt합니다. 실제로 현재 시점에서 내가 추천 할 유일한 것입니다. 강력한 검토를 거쳐 모든 결정을 내립니다 (매우 좋은 것입니다) ...

다음과 같은 것 :

use Zend\Crypt\BlockCipher;

public function createHash($password) {
    $hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>$this->cost]);

    $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
    $blockCipher->setKey($this->key);
    return $blockCipher->encrypt($hash);
}

public function verifyHash($password, $hash) {
    $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
    $blockCipher->setKey($this->key);
    $hash = $blockCipher->decrypt($hash);

    return password_verify($password, $hash);
}

그리고 모든 알고리즘을 잘 이해되고 잘 연구 된 방식 (적어도 상대적으로)으로 사용하고 있기 때문에 유용합니다. 생각해 내다:

가장 우둔한 아마추어부터 최고의 암호 전문가에 이르기까지 누구나 자신이 깰 수없는 알고리즘을 만들 수 있습니다.


6
이 상세한 답변에 대단히 감사합니다. 정말 도움이됩니다!
Frederik Kammer 2013 년

1
이 답변에 대한 칭찬입니다. 하나의 작은 간단한 선택이지만, 대부분의 사용자는 매우 약한 암호, 단어 및 암호를 해독하기 위해 사전에 포함 된 파생어를 사용합니다. 엔트로피를 잃지 않으려면 비밀번호와 후추를 연결하면됩니다. 그러나 해시 값 암호화에 대한 귀하의 제안은 아마도 서버 측 비밀을 추가하는 가장 좋은 솔루션 일 것입니다.
martinstoeckli

2
@martinstoeckli : 후추 의 개념에 대한 내 문제 는 그것의 가치에 있지 않습니다. "후추"의 응용 프로그램이 암호화 알고리즘 측면에서 미지의 영역에 들어간다는 점입니다. 그것은 좋은 일이 아닙니다. 대신, 암호화 기본 요소가 함께 작동하도록 설계된 방식으로 결합되어야한다고 생각합니다. 기본적으로 후추의 핵심 개념은 암호화에 대해 전혀 몰랐던 일부 사람들이 "더 많은 해시가 더 낫다! 소금이 있고 후추도 좋습니다!" 라고 말하는 것처럼 제 귀에 들립니다 . . 나는 오히려 더 간단하고, 더 테스트되고, 더 직관적 인 impl
ircmaxell

@ircmaxell-예, 귀하의 관점을 알고 있으며 나중에 해시 값이 암호화되는 한 동의합니다. 이 추가 단계를 수행하지 않으면 사전 공격은 좋은 해시 알고리즘을 사용하더라도 너무 많은 취약한 암호를 노출합니다.
martinstoeckli

@martinstoeckli : 동의하지 않습니다. 비밀을 저장하는 것은 쉬운 일이 아닙니다. 대신 좋은 비용 (오늘날 12 개)으로 bcrypt를 사용하면 가장 약한 암호 등급을 제외한 모든 암호가 안전합니다 (사전 및 사소한 암호가 약한 암호입니다). 그래서 저는 사람들에게 강도 측정기로 사용자를 교육하고 애초에 더 나은 암호를 사용하도록하는 데 집중할 것을 권장 합니다 ...
ircmaxell

5

암호를 후퇴하는 것은 확실히 좋은 일이지만 그 이유를 살펴 보겠습니다.

먼저 고추가 정확히 언제 도움이되는지 질문에 답해야합니다. 후추는 암호가 비밀로 유지되는 한 암호 만 보호하므로 공격자가 서버 자체에 액세스 할 수 있으면 아무 소용이 없습니다. 훨씬 더 쉬운 공격은 데이터베이스 (해시 값에 대한)에 대한 읽기 액세스를 허용하는 SQL 삽입입니다. 저는 SQL 삽입 데모를 준비하여 얼마나 쉬운 지 보여줍니다 (다음 화살표를 클릭하여 준비 입력).

그렇다면 후추는 실제로 무엇을 돕습니까? 고추가 비밀로 유지되는 한 사전 공격으로부터 취약한 암호를 보호합니다. 그러면 암호 12341234-p*deDIUZeRweretWy+.O. 이 비밀번호는 훨씬 길뿐만 아니라 특수 문자도 포함하며 사전에 포함되지 않습니다.

이제 사용자가 사용할 암호를 추정 할 수 있습니다. 암호가 64-72 자 사이 인 사용자가 있기 때문에 더 많은 사용자가 취약한 암호를 입력 할 것입니다 (실제로 이것은 매우 드뭅니다).

또 다른 요점은 무차별 대입의 범위입니다. sha256 해시 함수는 256 비트 출력 또는 1.2E77 조합을 반환합니다. 이는 GPU의 경우에도 무차별 대입에는 너무 많은 방법입니다 ( 제가 올바르게 계산했다면 2013 년에는 GPU에서 약 2E61 년 이 필요합니다 ). 그래서 우리는 후추를 적용하는 데 진정한 단점이 없습니다. 해시 값이 체계적이지 않기 때문에 일반적인 패턴으로는 무차별 대입 속도를 높일 수 없습니다.

추신 내가 아는 한 72 자 제한은 BCrypt 자체의 알고리즘에 따라 다릅니다. 내가 찾은 가장 좋은 대답은 이것 입니다.

PPS 귀하의 예제에 결함이 있다고 생각하며 전체 암호 길이로 해시를 생성하고 잘린 것으로 확인할 수 없습니다. 해시를 생성하고 해시를 확인하기 위해 동일한 방식으로 후추를 적용하려고했을 것입니다.


PPS와 관련하여 저는 다음과 같이 말할 수 있습니다. 예, 그는 잘리지 않은 암호의 해시로 잘린 암호를 확인할 수 있으며 여전히 true. 이것이 바로이 질문에 관한 것입니다. 직접 살펴보세요 : viper-7.com/RLKFnB
Sliq

@Panique-문제는 BCrypt 해시의 계산이 아니라 이전의 HMAC입니다. SHA 해시를 생성하기 위해 OP는 전체 길이 암호를 사용하고 결과를 BCrypt에 대한 입력으로 사용합니다. 확인을 위해 그는 SHA 해시를 계산하기 전에 암호를 자른 다음이 완전히 다른 결과를 BCrypt에 대한 입력으로 사용합니다. HMAC는 모든 길이의 입력을 허용합니다.
martinstoeckli

2

Bcrypt는 값 비싼 Blowfish 키 설정 알고리즘을 기반으로 한 알고리즘을 사용합니다.

bcrypt에 권장되는 56 바이트 암호 제한 (널 종료 바이트 포함)은 Blowfish 키의 448 비트 제한과 관련이 있습니다. 이 제한을 초과하는 바이트는 결과 해시에 완전히 혼합되지 않습니다. 따라서 bcrypt 암호에 대한 72 바이트 절대 제한은 해당 바이트가 결과 해시에 미치는 실제 효과를 고려할 때 관련성이 떨어집니다.

사용자가 일반적으로 55 바이트 이상의 비밀번호를 선택한다고 생각하는 경우, 비밀번호 테이블 위반시 보안을 강화하기 위해 항상 비밀번호를 늘리는 방법을 늘릴 수 있습니다. 문자). 사용자의 액세스 권한이 매우 중요하여 사용자가 일반적으로 매우 긴 암호를 요구하는 경우 암호 만료도 2 주와 같이 짧아야합니다. 즉, 해커가 일치하는 해시를 생성하는지 확인하기 위해 각 평가판 암호를 테스트하는 작업 요소를 무력화하는 데 자원을 투자하는 동안 암호가 유효하지 않을 가능성이 훨씬 적습니다.

물론 암호 테이블이 침해되지 않는 경우 해커가 사용자의 계정을 잠그기 전에 사용자의 55 바이트 암호를 추측하는 시도는 최대 10 회만 허용해야합니다.)

55 바이트보다 긴 암호를 사전 해시하기로 결정한 경우 제한을 초과하지 않고 최대 출력을 제공하므로 SHA-384를 사용해야합니다.


1
"암호 만료 기간도 2 주 정도로 짧아야합니다." "대규모 긴 암호"의 경우 실제로 암호를 저장하는 데 신경 쓰는 이유는 매번 암호 재설정을 사용하십시오. 진지하게, 그것은 잘못된 해결책입니다. 토큰을 사용한 2 단계 인증으로 이동하십시오.
zaph

감사합니다 @zaph. 저에게 그 예를 알려줄 수 있습니까? 흥미롭게 들리 네요.
Phil

[NIST 특별 출판물 800-63B 디지털 인증 가이드 라인 초안] ( pages.nist.gov/800-63-3/sp800-63b.html ), 5.1.1.2. 기억 된 비밀 검증 자 : 검증자는 기억 된 비밀을 임의로 (예 : 주기적으로) 변경하도록 요구해서는 안됩니다 . Jim Fenton의 Toward Better Password Requirements 도 참조하십시오 .
zaph

1
문제는 사용자가 비밀번호를 자주 변경해야할수록 최악의 비밀번호 선택이되어 보안이 저하된다는 것입니다. 사용자는 기억할 수있는 좋은 암호의 양이 제한되어 있으며 정말 나쁜 암호를 선택하거나 키보드 하단에 붙어있는 포스트잇 메모 등에
적는
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.