Bir sonraki değeri tahmin etme yeteneği, rand
neyin 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 rand
kendi 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_lcg
ile 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_lcg
burada ö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_lcg
biz çağrıldıktan sonra ortaya çıkan altıgen basamak baktığımızda gördüğümüz şeydir uniqid
gerç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_lcg
alabilirsiniz, 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 uniqid
ve / veya davranışının php_combined_lcg
değ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 srand
bir fikirden ne kadar korkunç olduğunu ve bu nedenle daha iyi değerler kullanması muhtemel olmadığını anlamaz.
mt_rand
Aynı sorundan da etkilendiğine dikkat çekmek önemlidir. mt_srand
Bilinen bir değerde tohumlama da öngörülebilir sonuçlar üretecektir. Entropininizden vazgeçmek openssl_random_pseudo_bytes
muhtemelen 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 uniqid
iç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_bytes
ve random_int
temel 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_bytes
Yalnı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 rand
ve mt_rand
her ç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.