Bir sonraki değeri tahmin etme yeteneği, randneyin neyle srandçağrıldığını belirleyebilme becerisine bağlıdır . Özellikle, önceden belirlenmiş bir sayıyla tohumlama srandöngörülebilir çıktı ile sonuçlanır ! PHP etkileşimli komut isteminden:
[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 >
Bu sadece bir şans değil. Çoğu platformda ** çoğu PHP sürümü * , 1024'te deyince 97, 97, 39, 77, 93 dizisini oluşturur .srand
Açıkçası, bu PHP ile ilgili bir sorun değil, bu randkendi uygulamasında bir sorun . Aynı sorun, Perl de dahil olmak üzere aynı (veya benzer) uygulamayı kullanan diğer dillerde de görülür.
İşin püf noktası, PHP'nin aklı başında herhangi bir sürümünün srand"bilinmeyen" bir değerle önceden ekilmiş olacağıdır . Oh, ama gerçekten bilinmiyor. Kimden ext/standard/php_rand.h:
#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
Yani, time()PID php_combined_lcgile tanımlanmış olan ve bunun sonucu olan bazı matematik ext/standard/lcg.c. Burada c & p gitmeyeceğim, gözlerim de parlıyordu ve avlanmayı bırakmaya karar verdim.
Bir miktar Google, PHP'nin diğer alanlarının en iyi rastgelelik oluşturma özelliklerine sahip olmadığını gösterir ve php_combined_lcgburada özellikle bu analizde öne çıkmaya çağırır :
Bu işlev ( gettimeofday) bize sadece gümüş bir tepside kesin bir sunucu zaman damgasını geri vermekle kalmaz , ayrıca "daha entropi" (PHP'den uniqid) talep edersek LCG çıktısı da ekler .
Evet buuniqid . Değeri görünüyor php_combined_lcgbiz çağrıldıktan sonra ortaya çıkan altıgen basamak baktığımızda gördüğümüz şeydir uniqidgerçek bir değere ikinci argüman setiyle.
Şimdi neredeydik?
Oh evet. srand.
Kod rasgele değerleri tahmin etmeye çalışıyorsanız Yani, yok diyoruz srand, sen sağladığı değerini belirlemek için ihtiyaç gidiyoruz php_combined_lcgalabilirsiniz, hangi (dolaylı?) Bir çağrı yoluyla uniqid. Bu değer el ile, değerin geri kalanını kaba bir şekilde zorlamak mümkündür - time()PID ve biraz matematik. Bağlantılı güvenlik sorunu oturumları kırmakla ilgili, ancak aynı teknik burada işe yarayacak. Yine, makaleden:
İşte yukarıda özetlenen saldırı adımlarının bir özeti:
- sunucunun yeniden başlatılmasını bekleyin
- uniqid değeri almak
- RNG tohumunu bu durumdan kaba kuvvet
- hedefin görünmesini beklemek için çevrimiçi durumu yokla
- Mevcut sunucu saatini ve RNG değerini takip etmek için unidid anketlerle interleave durum anketleri
- sorgulamada oluşturulan zaman ve RNG değer aralığını kullanan sunucuya karşı kaba kuvvet oturumu kimliği
Sadece bu son adımı gerektiği gibi değiştirin.
(Bu güvenlik sorunu, şu anda sahip olduğumuzdan (5.3.6) daha önceki bir PHP sürümünde (5.3.2) bildirilmiştir, bu nedenle davranışının uniqidve / veya davranışının php_combined_lcgdeğişmesi olasıdır , bu nedenle bu teknik artık uygulanabilir olmayabilir. YMMV.)
Öte yandan, üretmeye çalıştığınız kod el ile çağırıyorsasrand , sonuçtan çok daha iyi bir şey kullanmıyorlarsa , değeri tahmin etmek ve yerelinizi tohumlamak için php_combined_lcgçok daha kolay bir zaman geçirirsiniz. Doğru numaraya sahip jeneratör. El ile arayacak olan çoğu insan, bunun srandbir fikirden ne kadar korkunç olduğunu ve bu nedenle daha iyi değerler kullanması muhtemel olmadığını anlamaz.
mt_randAynı sorundan da etkilendiğine dikkat çekmek önemlidir. mt_srandBilinen bir değerde tohumlama da öngörülebilir sonuçlar üretecektir. Entropininizden vazgeçmek openssl_random_pseudo_bytesmuhtemelen daha güvenli bir bahis.
tl; dr: En iyi sonuçları elde etmek için, PHP rasgele sayı üretecini tohumlamayın ve iyiliğin iyiliği uniqidiçin kullanıcılara maruz bırakmayın . Bunlardan birini veya ikisini birden yapmak, rastgele sayılarınızın daha tahmin edilebilir olmasına neden olabilir.
PHP 7 Güncellemesi:
PHP 7.0 tanıtır random_bytesve random_inttemel işlevleri olarak. Temeldeki sistemin CSPRNG uygulamasını kullanırlar, bu da onları bir seri rasgele sayı üreticisinin yaşadığı sorunlardan arındırır. openssl_random_pseudo_bytesYalnızca bir uzantıya gerek duymadan etkili bir şekilde benzerler . PHP5 için bir polyfill kullanılabilir .
*: Suhosin güvenlik yaması davranışını değiştirir randve mt_randher çağrı ile böyle her zaman bu yeniden tohum. Suhosin üçüncü bir tarafça sağlanmaktadır. Bazı Linux dağıtımları bunu varsayılan PHP paketlerinde varsayılan olarak içerir, bazıları ise bir seçenek haline getirir ve diğerleri bunu tamamen görmezden gelir.
**: Kullanılan platforma ve temeldeki kütüphane çağrılarına bağlı olarak, burada belgelenenden farklı sekanslar üretilecektir, ancak Suhosin yaması kullanılmadıkça sonuçlar tekrarlanabilir olmalıdır.