기존 답변 중 일부가 가깝지만 다음 중 하나를 가지고 있기 때문에 답변을 게시하려고합니다.
- 같은 엔트로피에 대해 무차별 대입이 더 쉬워 지거나 암호가 더 길어 지도록 원하는 것보다 작은 문자 공간
- RNG 암호 학적으로 안전한 것으로 간주되지 않는다
- 일부 타사 라이브러리에 대한 요구 사항이며 직접 수행하는 데 필요한 내용을 보여주는 것이 흥미로울 수 있다고 생각했습니다.
이 답변은 count/strlen
생성 된 비밀번호 (최소 IMHO)의 보안이 사용자의 접근 방식을 초월 하므로 문제를 피할 수 있습니다. 또한 PHP> 5.3.0으로 가정하겠습니다.
문제를 다음과 같은 구성 부분으로 나누겠습니다.
- 임의의 데이터를 얻기 위해 안전한 임의의 소스를 사용하십시오.
- 해당 데이터를 사용하여 인쇄 가능한 문자열로 표시하십시오.
첫 번째 부분에서 PHP> 5.3.0은 함수를 제공합니다 openssl_random_pseudo_bytes
. 대부분의 시스템은 암호화 방식으로 강력한 알고리즘을 사용하지만 래퍼를 사용하도록 확인해야합니다.
/**
* @param int $length
*/
function strong_random_bytes($length)
{
$strong = false; // Flag for whether a strong algorithm was used
$bytes = openssl_random_pseudo_bytes($length, $strong);
if ( ! $strong)
{
// System did not use a cryptographically strong algorithm
throw new Exception('Strong algorithm not available for PRNG.');
}
return $bytes;
}
두 번째 부분에서는 base64_encode
바이트 문자열을 사용 하므로 원래 질문에 지정된 것과 매우 비슷한 알파벳을 갖는 일련의 문자를 생성하므로 사용합니다. 우리가 가진 마음을하지 않은 경우 +
, /
그리고 =
문자가 마지막 문자열에 표시하고 우리가 적어도 결과 원하는 $n
길이 자, 우리는 간단하게 사용할 수 있습니다 :
base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));
그 3/4
이유는 base64 인코딩으로 인해 바이트 문자열보다 길이가 3 분의 1 이상 큰 문자열이 생성되기 때문입니다. $n
그렇지 않으면 4 자에서 3 자까지의 길이가 길어 지므로 결과는 정확합니다 . 여분의 문자는 주로 패딩 문자이기 때문에 =
어떤 이유로 든 암호가 정확한 길이라는 제약이 있다면 원하는 길이로자를 수 있습니다. 이는 주어진 $n
암호에 대해 모든 암호가 동일한 수로 끝나기 때문에 결과 암호에 액세스 한 공격자가 추측 할 수있는 문자가 최대 2 개이기 때문입니다.
추가 크레딧을 위해 OP의 질문에서와 같이 정확한 사양을 충족하려면 조금 더 많은 작업을 수행해야합니다. 여기서는 기본 변환 방식을 포기하고 빠르고 더러운 방식으로 진행하겠습니다. 62 개 항목의 긴 알파벳 때문에 결과에 사용되는 것보다 더 많은 임의성을 생성해야합니다.
결과의 추가 문자의 경우 결과 문자열에서 단순히 문자를 버릴 수 있습니다. 바이트 열에서 8 바이트로 시작하면 base64 문자의 최대 약 25 %가이 "바람직하지 않은"문자가됩니다. 따라서이 문자를 버림으로써 원하는 OP보다 짧게 문자열을 만들 수 있습니다. 그런 다음 간단히 잘라서 정확한 길이로 얻을 수 있습니다.
$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);
더 긴 비밀번호를 생성하는 경우, 패딩 문자 =
는 중간 결과의 더 작은 비율을 형성하므로 PRNG에 사용 된 엔트로피 풀을 비우는 것이 문제가 될 경우 더 적은 접근 방식을 구현할 수 있습니다.