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

지난주에 암호 해싱에 대한 많은 기사를 읽었으며 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 통합만을 다룹니다. 의견 주셔서 감사합니다!



답변

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

문자 당 엔트로피

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

  • 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);
}

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

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


답변

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

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

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

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

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

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

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


답변

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

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

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

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

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


답변