PHP의 rand () 출력 예측


21

필자는 PHP의 rand () 출력이 PRNG로 예측 가능하다는 것을 여러 출처에서 읽었으며, 많은 곳에서 그것을 보았 기 때문에 사실 그대로 받아들입니다.

개념 증명에 관심이 있습니다. rand ()의 출력을 예측하는 방법은 무엇입니까? 이 기사를 읽음으로써 난수는 포인터 (시드)에서 시작하는 목록에서 반환 된 숫자라는 것을 이해하지만 이것이 어떻게 예측 가능한지 상상할 수 없습니다.

누군가 수천 번의 추측으로 주어진 순간에 rand ()를 통해 어떤 랜덤 #이 생성되었는지 합리적으로 알 수 있습니까? 또는 심지어 10,000 추측? 방법?

rand ()를 사용하여 암호를 잃어버린 사용자를위한 토큰을 생성하는 인증 라이브러리를 보았 기 때문에 이것이 잠재적 인 보안 허점이라고 가정했기 때문입니다. 그 이후로 메소드를 해시 openssl_random_pseudo_bytes(), orignal 해시 비밀번호 및 마이크로 시간 의 혼합 해시로 대체했습니다 . 이 작업을 수행 한 후 외부를보고 있으면 토큰이 rand ()의 md5라는 것을 알고 어떻게 추측하는지 알 수 없었습니다.


"그러나 이것이 어떻게 예측 가능한지 상상할 수 없습니다"? " en.wikipedia.org/wiki/Linear_congruential_generator를 먼저 읽고, 어떻게 예측할 수 있는지 상상할 수있게하세요. 그런 다음 질문을 수정하여 놀라움을 없애고 PHP의 리버스 엔지니어링의보다 실질적인 문제로 넘어갈 수 있습니다 작동 방식을 확인하기위한 랜드 함수 소스
S.Lott

"이것은 잠재적 인 보안 허점이라고 생각했습니다"? Evil Hacker가 사용자의 임의 비밀번호를 얻을 수있는 경우에만 레인보우 테이블을 사용하여 MD5 해시를 실행 취소하여 원래 (해시 전) 값을 복구 한 후 다음 비밀번호 요청을했는지 확인하십시오. 이론적으로 가능하다고 생각합니다. 그러나 임의의 숫자에 대한 레인보우 테이블이 작동하는 경우에만 가능합니다.
S.Lott

@ S.Lott-비밀번호 문제가 아닙니다. 시스템은 비밀번호를 재설정하고 URL에 사용되는 토큰을 이메일로 보냅니다. 토큰은 MD5 (rand ())를 통해 생성됩니다. rand ()의 출력을 예측할 수 있다면 원본에 대한 해시 나 원본을 알지 않고도 모든 사람의 암호를 변경할 수 있습니다.
Erik

@ 에릭. 권리. 도움이된다면 "랜덤 암호"를 "랜덤 토큰"으로 바꾸십시오. 누군가가 MD5 해시를 해제하여 난수를 복구하고 다음 난수를 얻도록 보장하는 경우에만 토큰을 남용 할 수 있습니다. 다음 랜드를 예측하는 것은 하나의 작은 부분 일뿐입니다. MD5를 취소하는 것은 어려운 부분입니다.
S.Lott

1
MD5 (rand ())는 rand ()와 동일한 보안 만 가지고 있습니다. 관련된 매우 제한된 수의 집합에 대해 MD5 (rand ())-> rand () 조회 테이블을 작성하는 것이 실용적입니다. rand ()의 제한된 도메인을 사용하면 반복 시도를 방지하는 메커니즘이 없으면 간단한 무차별 대입을 시도 할 수 있습니다.
MZB

답변:


28

다음 값을 추측하는 기능 rand은 무엇 srand을 호출 했는지 결정할 수있는 것과 관련 이 있습니다. 특히, 미리 결정된 수의 시딩 (seeding) srand은 예측 가능한 출력을 초래한다 ! PHP 대화식 프롬프트에서 :

[charles@charles-workstation ~]$ php -a
Interactive shell

php > srand(1024);
php > echo rand(1, 100);
97
php > echo rand(1, 100);
97
php > echo rand(1, 100);
39
php > echo rand(1, 100);
77
php > echo rand(1, 100);
93
php > srand(1024);
php > echo rand(1, 100);
97
php > echo rand(1, 100);
97
php > echo rand(1, 100);
39
php > echo rand(1, 100);
77
php > echo rand(1, 100);
93
php > 

이것은 단지 약간의 우연이 아닙니다. 대부분의 PHP 버전 * 대부분의 플랫폼에서 ** 순서 97, 97, 39, 77, 93이 생성됩니다srand 'D 1024를.

분명히, 이것은 PHP의 문제가 아니며, 이것은 구현의 문제입니다. rand 자체 . Perl을 포함하여 동일한 (또는 유사한) 구현을 사용하는 다른 언어에서도 동일한 문제가 나타납니다.

비결은 PHP의 제정신 버전에 srand"알 수없는"값 이 미리 설정되어 있다는 것 입니다. 아, 그러나 그것은 실제로 알려지지 않았습니다. 보낸 사람 ext/standard/php_rand.h:

#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))

따라서, time()PID 및의 결과 php_combined_lcg는에 정의 된 수학입니다 ext/standard/lcg.c. 나는 여기에 c & p를하지 않을 것입니다. 또한, 내 눈이 번쩍이고 사냥을 중단하기로 결정했습니다.

인터넷 검색의 것을 쇼의 비트 PHP의 다른 지역 최고의 랜덤 생성 특성이없는 , 그리고 호출하는 php_combined_lcg, 여기 분석, 특히이 비트를 밖으로 서 :

이 함수 gettimeofday는은 플래터에 정확한 서버 타임 스탬프를 되돌려 줄뿐만 아니라 "더 많은 엔트로피"(PHP에서 uniqid)를 요청하면 LCG 출력을 추가합니다 .

그래, uniqid . 두 번째 인수를 true로 설정하여 php_combined_lcg호출 한 후 결과 16 진수를 볼 때 볼 수있는 값 인 것 같습니다 uniqid.

자, 우리는 어디에 있었습니까?

아, 네. srand.

따라서 임의의 값을 예측하려는 코드 호출 하지 않으면srand 에 의해 제공되는 값을 결정해야합니다.이 값은에 php_combined_lcg대한 호출을 통해 (간접적으로?) 얻을 수 있습니다 uniqid. 그 가치를 손 에 넣으면 나머지 값 , PID 및 수학 을 무차별 대입하는 것이 가능 합니다 time(). 연결된 보안 문제는 세션을 중단하는 것과 관련이 있지만 동일한 기술이 여기에서 작동합니다. 다시 기사에서 :

위에서 설명한 공격 단계를 요약하면 다음과 같습니다.
  • 서버가 재부팅 될 때까지 기다리십시오
  • uniqid 값을 가져옵니다
  • 이로부터 RNG 종자를 무차별 대입
  • 대상이 나타날 때까지 온라인 상태를 폴링
  • 현재 서버 시간 및 RNG 값을 추적하기 위해 uniqid 폴링으로 상태 폴링을 인터리브
  • 폴링에서 설정된 시간 및 RNG 값 간격을 사용하여 서버에 대한 무차별 강제 세션 ID

필요에 따라 마지막 단계를 교체하십시오.

(이 보안 문제는 현재 (5.3.6)보다 이전 PHP 버전 (5.3.2)에서보고되었으므로 동작 uniqid및 / 또는 php_combined_lcg변경 되었을 수 있으므로이 특정 기술은 더 이상 작동하지 않을 수 있습니다. YMMV.)

반면, 제품을 만들려고하는 코드 srand수동으로 호출 하는 경우 결과보다 몇 배 더 나은 것을 사용하지 않는 한 값을 추측하고 지역을 파종하는 것이php_combined_lcg 훨씬 쉬울 것입니다. 올바른 번호의 발전기. 수동으로 전화하는 대부분의 사람들srand 이것이 얼마나 끔찍한 아이디어인지 알지 못하므로 더 나은 가치를 사용하지 않을 것입니다.

mt_rand동일한 문제로 인해 어려움을 겪고 있음을 주목할 가치가 있습니다. mt_srand알려진 값으로 시드 하면 예측 가능한 결과가 생성됩니다. 엔트로피를 기반으로하는 openssl_random_pseudo_bytes것이 아마도 더 안전한 내기 일 것입니다.

tl; dr : 최상의 결과를 얻으려면 PHP 난수 생성기를 시드하지 말고 좋은 결과를 얻으 uniqid려면 사용자에게 노출하지 마십시오 . 이들 중 하나 또는 둘 다를 수행하면 난수가 더 추측 가능할 수 있습니다.


PHP 7 업데이트 :

PHP 7.0 출시 random_bytesrandom_int핵심 기능으로. 기본 시스템의 CSPRNG 구현을 사용하여 시드 난수 생성기의 문제점을 제거합니다. openssl_random_pseudo_bytes확장 기능을 설치하지 않고도 효과적으로와 유사합니다 . 폴리 필은 PHP5에 사용할 수 있습니다 .


* : Suhosin 보안 패치randmt_rand 모든 호출과 같은 그들은 항상 것을 다시 씨앗을. Suhosin은 타사에서 제공합니다. 일부 Linux 배포판은 기본적으로 공식 PHP 패키지에 포함하지만 다른 배포판은 옵션으로 만들고 나머지는 완전히 무시합니다.

** : 사용중인 플랫폼 및 기본 라이브러리 호출에 따라 여기에 설명 된 것과 다른 시퀀스가 ​​생성되지만 Suhosin 패치를 사용하지 않으면 결과를 계속 반복 할 수 있습니다.


감사합니다 Charles-귀하의 답변과 Tangurena의 선형 합동 생성기 링크를 읽는 것 사이에 더 잘 이해하고 있다고 생각합니다. 나는 이런 방식으로 rand ()를 사용하는 것이 좋지 않다는 것을 이미 알고 있었다. 그러나 내가 왜 그런지 알고있다 .
에릭

와우, 철저한 철자법을위한 도구는 고마워요!
David Hobs

10

비 랜덤 화 방법을 시각적으로 설명하기 위해 rand()함수가 모든 픽셀이 "랜덤"빨강, 녹색 및 파랑 값으로 구성된 이미지는 다음과 같습니다.

임의의 RGB 값

이미지에는 일반적으로 패턴이 없어야합니다.

나는 전화를 시도했다 srand()다른 값으로 이 함수의 예측 가능성은 변경되지 않습니다.

둘 다 암호화로 안전하지 않으며 예측 가능한 결과를 생성합니다.


7

PHP의 rand () 출력은 PRNG로 예측 가능

그것은 인 선형 합동 생성기 . 그것은 당신이 효과적으로 기능하는 것을 의미합니다 : NEW_NUMBER = (A * OLD_NUMBER + B) MOD C. NEW_NUMBER 대 OLD_NUMBER을 (를) 차트로 표시하면 대각선이 보이기 시작합니다. PHP의 RAND 문서 에 대한 참고 사항 중 일부 는 그렇게하는 방법에 대한 예를 제공합니다.

rand ()를 사용하여 암호를 잃어버린 사용자를위한 토큰을 생성하는 인증 라이브러리를 보았 기 때문에 이것이 잠재적 인 보안 허점이라고 가정했기 때문입니다.

Windows 시스템에서 RAND의 최대 값은 2 ^ 15입니다. 이로 인해 공격자는 32,768 개의 가능성 만 확인할 수 있습니다.

누군가 수천 번의 추측으로 주어진 순간에 rand ()를 통해 어떤 랜덤 #이 생성되었는지 합리적으로 알 수 있습니까? 또는 심지어 10,000 추측? 방법?

하지만 이 문서는 정확하게 당신이 찾고있는 것이 아니다, 일부 연구자들은 난수 발생기의 기존 구현을 데리고 텍사스 홀덤에 돈을 벌기 위해 그것을 사용하는 방법을 보여줍니다. 52 개 있습니다! 가능한 셔플 데크가 있지만 구현에는 32 비트 난수 생성기 (Windows 시스템의 mt_getrandmax에서 최대 수)를 사용하여 자정 이후 밀리 초 단위로 시드했습니다. 이것은 가능한 셔플 데크의 수를 약 2 ^ 226에서 약 2 ^ 27로 감소시켜 실시간으로 검색하고 어떤 데크가 처리되었는지 알 수있었습니다.

이 작업을 수행 한 후 외부를보고 있으면 토큰이 rand ()의 md5라는 것을 알고 어떻게 추측하는지 알 수 없었습니다.

피드가 md5가 고장난 것으로 간주 하므로 SHA-2 제품군 에서 무언가를 사용하는 것이 좋습니다 . 일부 사람들은 Google을 사용하여 md5 해시를 해독하기 때문에 일반적입니다. 해시를 해시 한 다음 해시를 구글 검색에 넣습니다. 기본적으로 구글은 거대한 무지개 테이블이되었습니다 .


1

무작위로 생성 된 숫자가 주어지면 다음 숫자는 상대적으로 예측 가능하다고 말하는 것이 실제로 더 정확합니다. 숫자가 너무 많습니다. 그렇다고해서 추측 할 수있는 것은 아니며, 더 빠른 프로그램을 작성할 수 있다는 것입니다.


1
다음 숫자는 전적으로 결정적이라고 생각합니다. "상대적으로"가 아니라 절대적으로. 의사 난수 생성기의 문제점은 시퀀스가 ​​통계 테스트를 통과한다는 것입니다. 두 개의 인접한 숫자는 완전히 결정적이지만 실제 난수와 공통 인 통계적 속성을 가질 수 있습니다.
S.Lott

1
다음 숫자는 전적으로 결정적입니다. 이것이 의사 난수 생성기의 "의사"가 의미하는 바입니다. 다른 한편으로, 다음 숫자가 실제로 획득하기가 불가능하다는 것을 결정하기 위해 필요한 정보.
Rein Henrichs

@ S.Lott-2 ^ 32 가능한 출력에서 ​​숫자가 여러 번 나타날 수 있으며 나타날 때마다 다른 숫자가 나타날 수 있다는 인상을 받았습니다. 그러나 X의 시드가 주어지면 Y의 결과를 반환하면 다음 결과는 항상 동일합니다. 따라서 실제로 Y 뒤에 오는 소수의 숫자가있을 수 있습니다. 그래도 잘못되었을 수 있습니다. PRNG를 실제로 본 이후 오랜 시간이 걸렸습니다.
pdr
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.