Kısaca cevap
Bilgisayarlar belirlenimci çalıştığı için çoğunlukla bir başlangıç değerinden (tohum) sayı dizisi üreten algoritmalar kullanır. Oyun ve simülasyon için hızlı PRNG yeterlidir; şifre ve anahtar için ise işletim sisteminin fiziksel gürültüden beslenen CSPRNG'si gerekir. Tarayıcıda bu, Math.random() değil crypto.getRandomValues() demektir.
Bu sayfada
Rastgele sayı üreteci nedir?
Rastgele sayı üreteci (İngilizcede random number generator, RNG), önceden tahmin edilemeyen sayılar üretmek için kullanılan algoritma veya donanımdır. Zar atan bir oyun, çekiliş yapan bir site, kupon kodu dağıtan bir mağaza ya da şifre üreten bir araç, arka planda bir rastgele sayı üretecine başvurur. Üreteçlerin hepsi aynı kalitede değildir: bir oyun için yeterli olan üreteç, şifre üretmek için tehlikeli olabilir. Bu yazının geri kalanı bu farkı anlatıyor.
Bilgisayar neden kendi başına rastgele olamaz?
Bir bilgisayar programı aynı girdiyle her çalıştığında aynı sonucu verir; buna belirlenimcilik denir. Hata ayıklamak için harika bir özelliktir, ama rastgele sayı üretmek için bir sorundur. Bu yüzden bilgisayarlarda rastgelelik iki yoldan sağlanır: ya dış dünyadan ölçülen öngörülemez bir fiziksel olaydan yararlanılır ya da rastgele görünen sayılar üreten bir algoritma kullanılır. Pratikte ikisi birlikte kullanılır.
Rastgeleliğin genel tanımını merak ediyorsanız Rastgelelik Nedir? yazısına göz atabilirsiniz.
Rastgele sayı üreteci türleri: PRNG, CSPRNG ve TRNG
| Tür | Nasıl çalışır? | Örnekler | Nerede kullanılır? |
|---|---|---|---|
| PRNG (sözde rastgele sayı üreteci) | Bir tohumdan başlayıp matematiksel formülle dizi üretir. Hızlıdır, ama çıktıları gözlemlenerek iç durumu çözülebilir. | Mersenne Twister (Python random), java.util.Random, System.Random, çoğu tarayıcıda Math.random() | Oyunlar, simülasyonlar, testler |
| CSPRNG (kriptografik olarak güvenli PRNG) | Tahmin edilemezlik için tasarlanmış algoritma; işletim sisteminin topladığı entropiyle tohumlanır ve düzenli olarak yeniden beslenir. | crypto.getRandomValues(), Python secrets, Java SecureRandom, C# RandomNumberGenerator, PHP random_int() | Şifre, anahtar, oturum belirteci, doğrulama kodu |
| TRNG (gerçek / donanımsal rastgele sayı üreteci) | Isıl gürültü, saat titreşimi gibi fiziksel olayları ölçer. | İşlemci içindeki donanım üreteçleri, özel USB cihazları | CSPRNG'yi tohumlamak için entropi kaynağı |
Sözde rastgele ne demek? Tohum (seed) ve iç durum
"Sözde rastgele" ifadesi, sayıların gerçekten rastgele olmadığını, yalnızca öyle göründüğünü anlatır. PRNG'nin ürettiği her sayı bir önceki iç durumdan formülle hesaplanır; istatistik testlerinde düzgün dağılmış görünse de süreç baştan sona belirlenimcidir.
Bir PRNG'nin ürettiği dizinin tamamı tohum tarafından belirlenir. Aynı tohumla başlatılan iki üreteç birebir aynı sayıları üretir. Bu, bir simülasyonu tekrarlamak için kullanışlıdır; güvenlikte ise ciddi bir açıktır. Eskiden sık yapılan bir hata, üreteci o anki saatle tohumlamaktır: saldırgan şifrenin yaklaşık ne zaman üretildiğini biliyorsa olası tohumları tek tek deneyerek aynı şifreyi yeniden üretebilir.
İkinci sorun iç durumdur. Örneğin Mersenne Twister, yeterince ardışık çıktısı gözlemlenirse iç durumu tamamen hesaplanabilen bir algoritmadır; bundan sonra üreteceği tüm sayılar bilinir. Python'daki MT19937 için ardışık 624 adet 32 bitlik çıktı bunun için yeterlidir. Python belgesi de bu yüzden random modülünün güvenlik amaçlı kullanılmamasını, bunun yerine secrets modülünün kullanılmasını önerir.
Entropi: Rastgeleliğin hammaddesi
Entropi, bir kaynağın ne kadar öngörülemez olduğunun ölçüsüdür ve bit ile ifade edilir. 1 bit entropi, yazı tura kadar belirsizlik demektir; her ek bit olasılık sayısını iki katına çıkarır. İşletim sistemleri entropiyi donanım kesmelerinin zamanlaması, disk ve ağ olaylarındaki küçük gecikmeler ve işlemcinin donanım üreteci gibi kaynaklardan toplar. Bu ham veri doğrudan kullanılmaz; bir CSPRNG'ye tohum olarak verilir.
Uygulamalar da işletim sisteminin bu hazır üretecini kullanmalıdır:
- Linux:
getrandom()sistem çağrısı ve/dev/urandomaygıtı. Güncel çekirdeklerde, üreteç başlangıçta yeterince tohumlandıktan sonra/dev/randomile/dev/urandomarasındaki pratik fark büyük ölçüde ortadan kalkmıştır:getrandom()Linux 3.17 ile geldi, Linux 5.6'dan beri de/dev/randomyalnızca açılışın erken aşamasında bekletir. - Windows: CNG kütüphanesindeki
BCryptGenRandomişlevi. - macOS ve iOS:
getentropy(),arc4random()veSecRandomCopyBytesgibi arayüzler.
Tarayıcılardaki crypto.getRandomValues() ve programlama dillerinin güvenli işlevleri de arka planda bu işletim sistemi kaynaklarına dayanır.
Fiziksel dünyadan entropi toplamanın ilginç örnekleri de vardır. Cloudflare, San Francisco ofisinin lobisindeki lav lambalarını kamerayla görüntüleyen LavaRand adlı sistemi, sunucularına ek bir entropi kaynağı olarak kullanır. Şirketin açıklamasına göre bu görüntülerden elde edilen veri, sunucunun kendi entropi sistemiyle karıştırılır; amaç, yerel kaynaklardan biri zayıflasa bile güvenli rastgeleliğin sürmesidir. Yani lav lambaları tek kaynak değil, derinlemesine savunmanın bir katmanıdır.
Math.random() ile crypto.getRandomValues() farkı
JavaScript'teki Math.random(), 0 ile 1 arasında bir ondalık sayı döndürür ve belirtimi gereği kriptografik güvenlik vaat etmez. Tarayıcıların çoğu burada hızlı bir PRNG kullanır; örneğin Chrome'un JavaScript motoru V8, Chrome 49'dan beri xorshift128+ algoritmasını kullanıyor. Çıktıları gözlemlenerek sonraki değerlerin tahmin edildiği saldırılar gösterilmiştir. Oyun ya da animasyon için sorun yoktur; şifre, kupon kodu veya oturum belirteci için kullanılmamalıdır.
crypto.getRandomValues() ise Web Crypto API'nin bir parçasıdır ve verdiğiniz tam sayı dizisini kriptografik olarak güvenli rastgele değerlerle doldurur:
// 32 bitlik güvenli rastgele bir tam sayı
const buf = new Uint32Array(1);
crypto.getRandomValues(buf);
console.log(buf[0]);
Tek çağrıda istenebilecek veri miktarının bir üst sınırı vardır; şifre üretimi gibi işler bu sınırın (65.536 bayt) çok altında kalır. Kullanımını JavaScript ile rastgele şifre üretici yazımızda; Python, C#, Java ve PHP karşılıklarını da aynı serideki diğer yazılarımızda örnek kodlarla bulabilirsiniz.
Modulo sapması ve reddetme örneklemesi
Güvenli bir kaynak kullanmak tek başına yetmez; gelen sayıyı istediğiniz aralığa nasıl indirgediğiniz de önemlidir. En yaygın hata, sayının mod alınmasıdır. 0-255 arasında rastgele bir bayttan 0-9 arası bir rakam üretmek istediğinizi düşünün: 256 sayı 10'a tam bölünmez (256 = 25 × 10 + 6). Sonuç olarak 0-5 arasındaki rakamlar 26'şar, 6-9 arasındakiler 25'er değere karşılık gelir. Yani 0-5 arasındaki rakamların gelme olasılığı 26/256, diğerlerininki 25/256 olur. Buna modulo sapması denir.
Tek bir şifrede bu fark küçük görünür, ama saldırganın deneme sırasını ve istatistiksel analizleri etkiler; kaldı ki önlemesi çok kolaydır. Çözüm reddetme örneklemesidir: aralığa tam bölünebilen en büyük sınırın üstünde kalan değerler atılır ve yeni bir sayı çekilir.
// [0, max) aralığında sapmasız güvenli tam sayı
function randomInt(max) {
const limit = Math.floor(0x100000000 / max) * max; // 2^32'nin altındaki en büyük max katı
const buf = new Uint32Array(1);
let x;
do {
crypto.getRandomValues(buf);
x = buf[0];
} while (x >= limit); // sınırın üstündekileri reddet
return x % max;
}
Bu yöntemde reddedilen değerlerin oranı çok küçüktür; örneğin 87 karakterlik bir havuzdan seçim yaparken yeniden çekme ihtiyacı neredeyse hiç doğmaz. Sitemizdeki araçlar da bu yaklaşımı kullanır: 32 bitlik güvenli bir sayı alınır, sınırın üstündeyse atılır ve kalan değerin modu alınır.
Yazılımcıların sık yaptığı rastgelelik hataları
Güvenlik açıklarının önemli bir kısmı, kötü algoritmalardan değil, doğru araçların yanlış kullanılmasından doğar. Kod incelemelerinde en sık karşılaşılan hatalar şunlardır:
- Genel amaçlı üreteci güvenlik için kullanmak: Şifre sıfırlama bağlantısındaki kodu, API anahtarını veya kupon kodunu
Math.random(), Pythonrandomya daSystem.Randomile üretmek. - Üreteci zamanla tohumlamak: Tohum olarak saat veya işlem numarası kullanmak, olası tohum sayısını saldırganın deneyebileceği kadar küçültür.
- Her çağrıda yeni üreteç oluşturmak: Bazı dillerde aynı anda oluşturulan iki genel amaçlı üreteç aynı tohumu alıp aynı sayıları üretebilir. Örneğin .NET Framework'te art arda oluşturulan
new Random()örnekleri, sistem saatinden aynı tohumu alabilir. - Mod alarak aralığa indirgemek: Yukarıda anlatılan modulo sapmasını doğurur.
- Kendi algoritmasını yazmak: "Biraz karıştırırsam kimse çözemez" yaklaşımı neredeyse her zaman işletim sisteminin test edilmiş üretecinden daha zayıf sonuç verir.
- Rastgele değeri kaydetmek veya loglamak: Üretilen şifre ya da anahtar günlük dosyalarına yazılırsa üretecin kalitesinin bir önemi kalmaz.
Kural basittir: güvenlikle ilgili her değer için dilinizin kriptografik işlevini kullanın, gerisini ona bırakın.
Sitemizdeki araçlar rastgeleliği nasıl sağlıyor?
Şifre, parola, PIN ve sayı üreten tüm araçlarımız aynı çekirdeği kullanır: tarayıcınızın crypto.getRandomValues() API'si + reddetme örneklemesi. Karakterlerin karıştırılması için sapmasız Fisher–Yates algoritması uygulanır. Üretim tamamen sizin cihazınızda yapılır; sonuçlar sunucuya gönderilmez ve kaydedilmez.
- Şifre üretici: harf, rakam ve sembollerden rastgele şifre.
- Akılda kalır parola üretici: Türkçe kelimelerden parola.
- Rastgele sayı üretici ve PIN üretici.
- Sayısal loto sayı üretici: Çılgın Sayısal, Süper Loto ve Şans Topu için rastgele sayı. Rastgele seçim kazanma olasılığını değiştirmez; yalnızca sayıları sizin yerinize tarafsızca seçer. Şans oyunları 18 yaşından küçükler için yasaktır.
Kendi uygulamanızda şifre, doğrulama kodu veya anahtar üretiyorsanız "rastgele" adlı ilk işlevi değil, dilinizin kriptografik üretecini kullanın ve aralığa indirgerken mod sapmasına dikkat edin. Kriptografinin rastgeleliğe neden bu kadar bağımlı olduğunu Kriptografi ve Rastgelelik yazısında anlatıyoruz.
Sık sorulan sorular
PRNG ile CSPRNG arasındaki fark nedir?
İkisi de bir başlangıç değerinden (tohum) sayı dizisi üreten algoritmalardır. PRNG hızlı ve istatistiksel olarak düzgün dağılımlıdır ama çıktılarından iç durumu tahmin edilebilir. CSPRNG ise önceki çıktılar bilinse bile sonrakinin tahmin edilemeyeceği şekilde tasarlanır ve işletim sisteminin entropi kaynaklarıyla beslenir. Şifre, anahtar ve oturum kodu için yalnızca CSPRNG kullanılmalıdır.
Math.random() ile şifre üretmek güvenli mi?
Hayır. Math.random() kriptografik güvenlik için tasarlanmamıştır ve tarayıcıların çoğunda hızlı bir PRNG kullanır. Şifre veya güvenlik kodu üretirken tarayıcıda crypto.getRandomValues(), Python'da secrets, Java'da SecureRandom, C#'ta RandomNumberGenerator gibi kriptografik kaynaklar kullanılmalıdır.
Modulo sapması (modulo bias) nedir?
Rastgele bir sayıyı mod alarak küçük bir aralığa indirgediğinizde, aralık büyüklüğü kaynak aralığı tam bölmüyorsa bazı değerler diğerlerinden biraz daha sık gelir. Örneğin 0-255 arasındaki bir baytın 10'a göre modunu alırsanız 0-5 rakamları 26, 6-9 rakamları 25 kez temsil edilir. Reddetme örneklemesi bu sapmayı tamamen ortadan kaldırır.
Sözde rastgele sayı ne demek?
Sözde rastgele (pseudo-random) sayılar, bir başlangıç değerinden (tohum) matematiksel bir formülle üretilen ve rastgele görünen sayılardır. Aynı tohumla başlatılan üreteç her seferinde aynı diziyi verir; yani sonuçlar aslında belirlenmiştir, yalnızca tohumu bilmeyen biri için rastgele görünür.
Gerçek rastgele sayı üreteci (TRNG) daha mı güvenli?
Tek başına şart değildir. İşletim sistemleri donanım gürültüsü gibi fiziksel kaynaklardan topladığı entropiyi bir CSPRNG'ye tohum olarak verir; doğru tohumlanmış bir CSPRNG'nin çıktısı pratikte gerçek rastgelelikten ayırt edilemez. Ham fiziksel kaynaklar çoğunlukla doğrudan değil, bu şekilde işlenerek kullanılır.