Kısaca cevap
JavaScript'te şifre üretirken Math.random() yerine tarayıcıda crypto.getRandomValues(), Node.js'te crypto.randomInt() kullanın. Rastgele sayıyı karakter havuzuna indirgerken basit mod alma işlemi bazı karakterleri daha sık seçtirir; bunu önlemek için aşağıdaki reddetme örneklemeli fonksiyonu kullanın. Kodlar Node.js 24 ile çalıştırılarak denendi; jQuery veya başka bir kütüphaneye gerek yoktur.
Bu sayfada
Math.random neden şifre için uygun değil?
Math.random() animasyon, oyun ve örnek veri için yeterince iyidir ama kriptografik olarak güvenli değildir. Tarayıcılar bu fonksiyon için hızlı sözde rastgele algoritmalar kullanır ve yeterli sayıda çıktıyı gören biri sonraki değerleri tahmin edebilir. MDN belgeleri de güvenlikle ilgili işlerde Math.random() yerine Web Crypto API'nin kullanılmasını söyler.
Eski örneklerde sık görülen Math.floor(Math.random() * chars.length) kalıbı bu yüzden şifre, token veya doğrulama kodu üretmek için kullanılmamalıdır. Güvenli alternatif crypto.getRandomValues()'tur: işletim sisteminin kriptografik rastgele sayı kaynağından beslenir ve tüm güncel tarayıcılarda bulunur. Teorik arka planı kriptografi ve rastgelelik yazısında okuyabilirsiniz.
Modulo sapması ve reddetme örneklemesi
getRandomValues size karakter değil, sayı verir. Bu sayıyı havuzdaki bir karaktere çevirmenin ilk akla gelen yolu mod almaktır (sayi % havuz.length). Sorun, sayı aralığı havuz boyutuna tam bölünmediğinde ortaya çıkar.
Örneğin 0–255 arası bir bayt (Uint8Array) ile 77 karakterlik bir havuz kullandığınızı düşünün. 256 = 3 × 77 + 25 olduğu için havuzun ilk 25 karakteri 256'da 4, geri kalanlar 256'da 3 olasılıkla seçilir. Yani bazı karakterler yaklaşık üçte bir daha sık çıkar.
Çözüm reddetme örneklemesidir: havuz boyutunun katı olan en büyük sınırı hesaplayın, bu sınırın üstünde kalan sayıları atıp yeniden çekin. Kalan sayıların hepsi havuza eşit dağılır. Bu sitedeki şifre üretici de aynı yöntemi kullanır.
JavaScript ile rastgele şifre oluşturucu (tarayıcı)
Aşağıdaki kod tarayıcıda ve güncel Node.js sürümlerinde global crypto nesnesiyle olduğu gibi çalışır:
// 0 ile max-1 arasında, modulo sapması olmadan güvenli tamsayı
function guvenliSayi(max) {
const sinir = Math.floor(0x100000000 / max) * max; // 2^32'nin max'a bölünebilen kısmı
const kutu = new Uint32Array(1);
let x;
do {
crypto.getRandomValues(kutu);
x = kutu[0];
} while (x >= sinir); // sınırın üstündeki değerleri at, yeniden çek
return x % max;
}
function sifreUret(uzunluk = 16) {
const alfabe =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+?";
let sifre = "";
for (let i = 0; i < uzunluk; i++) {
sifre += alfabe[guvenliSayi(alfabe.length)];
}
return sifre;
}
console.log(sifreUret());
console.log(sifreUret(24));
Örnek çıktı (her çalıştırmada farklı olur):
Nu?)TA1sj26^xSo5
9Dnf2a^lsq5EvKw3Hfieg8FW
32 bitlik sayı kullanıldığı için atılan değer oranı çok küçüktür; döngü pratikte neredeyse her zaman ilk denemede biter. guvenliSayi(7) fonksiyonunu 700.000 kez çalıştırdığımızda her değer yaklaşık 100.000 kez çıktı, yani dağılım dengeli.
Bir çağrıda en fazla 65.536 baytlık dizi doldurulabilir; daha büyük bir dizi verirseniz tarayıcı hata fırlatır. Şifre üretmek için bu sınıra hiç yaklaşmazsınız, ama çok sayıda değeri tek seferde üretecek bir kod yazıyorsanız diziyi parçalara bölün. Ayrıca getRandomValues yalnızca tamsayı dizileriyle çalışır; Float32Array gibi ondalıklı dizilerle kullanılamaz.
JavaScript random string: belirli uzunlukta rastgele string
Her zaman şifre gerekmez; bazen bir dosya adı, davet kodu veya test verisi için belirli uzunlukta, yalnızca harf ve rakamdan (alfanümerik) oluşan bir string istersiniz. Aynı guvenliSayi fonksiyonuyla bunu genel amaçlı bir fonksiyona dönüştürebilirsiniz:
// Belirli uzunlukta rastgele string (varsayılan: 10 karakter, harf + rakam)
function rastgeleString(
uzunluk = 10,
alfabe = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
) {
let sonuc = "";
for (let i = 0; i < uzunluk; i++) {
sonuc += alfabe[guvenliSayi(alfabe.length)];
}
return sonuc;
}
console.log(rastgeleString()); // 10 karakter, alfanümerik
console.log(rastgeleString(8, "0123456789ABCDEF")); // 8 karakter, onaltılık
Örnek çıktı (her çalıştırmada farklı olur):
4986Yarmd5
485F1E59
Fonksiyonu 10.000 kez çalıştırdık; her çıktı tam 10 karakterdi ve yalnızca harf ile rakam içeriyordu. Alfabe olarak yalnızca standart harf, rakam ve sembol kullanın; emoji gibi birden fazla kod birimi tutan karakterler bu basit indekslemeyle bölünebilir.
Diziden rastgele eleman seçmek
Bir listeden (dizi) rastgele bir eleman seçmek de aynı mantıkla yapılır: dizinin uzunluğu kadar aralıkta sapmasız bir sayı çekip o sıradaki elemanı alırsınız.
function rastgeleSec(dizi) {
if (dizi.length === 0) throw new RangeError("Dizi boş olamaz");
return dizi[guvenliSayi(dizi.length)];
}
console.log(rastgeleSec(["elma", "armut", "kiraz"]));
Bu fonksiyonu üç elemanlı bir diziyle 30.000 kez çalıştırdığımızda her eleman yaklaşık 10.000 kez seçildi. Kura veya çekiliş gibi işler için kod yazmadan rastgele sayı üretici aracını da kullanabilirsiniz.
Math.random().toString(36) neden iyi bir yol değil?
İnternette sık görülen Math.random().toString(36).substring(2, 12) kalıbı kısa ve pratik görünür, ama iki sorunu vardır. Birincisi, Math.random() kriptografik olarak güvenli değildir. İkincisi, sonuç her zaman istediğiniz uzunlukta çıkmaz: sayının 36 tabanındaki gösterimi kısaysa daha az karakter alırsınız. Örneğin (0.5).toString(36) yalnızca "0.i" verir. Node.js 24'te bu kalıbı 100.000 kez çalıştırdığımızda, sonuçların küçük bir kısmı 10 yerine 7, 8 veya 9 karakter çıktı. Ayrıca yalnızca küçük harf ve rakam içerir. Yukarıdaki rastgeleString fonksiyonu bu sorunların hiçbirini taşımaz.
Her karakter türünü garanti etmek
"En az bir büyük harf, bir rakam ve bir özel karakter" isteyen siteler için önce her gruptan bir karakter seçip kalanını tüm havuzdan doldurun, ardından Fisher–Yates algoritmasıyla karıştırın:
function gucluSifre(uzunluk = 16) {
const gruplar = [
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"!@#$%^&*()-_=+?",
];
if (uzunluk < gruplar.length) {
throw new RangeError("Uzunluk en az " + gruplar.length + " olmalı");
}
const tum = gruplar.join("");
const secilen = gruplar.map((g) => g[guvenliSayi(g.length)]);
while (secilen.length < uzunluk) {
secilen.push(tum[guvenliSayi(tum.length)]);
}
// Fisher–Yates karıştırma (güvenli rastgele sayı ile)
for (let i = secilen.length - 1; i > 0; i--) {
const j = guvenliSayi(i + 1);
[secilen[i], secilen[j]] = [secilen[j], secilen[i]];
}
return secilen.join("");
}
for (let i = 0; i < 3; i++) console.log(gucluSifre(16));
Örnek çıktı (her çalıştırmada farklı olur):
oYO1@9Nvhi6P*zjC
dOZQmP9J*PhA2SaB
J9$pj=Mh8Hct4lDx
Bu fonksiyon önceki örnekteki guvenliSayi fonksiyonunu kullanır. Karıştırma adımında da guvenliSayi kullanılması önemlidir; array.sort(() => Math.random() - 0.5) gibi kısa yollar hem güvensiz hem de dengesizdir. Fonksiyonu 4 karakter uzunluğunda 10.000 kez çalıştırdık; her çıktıda dört türün de bulunduğunu doğruladık.
Düğmeye bağlamak (jQuery gerekmez)
Eski örneklerde şifre üretici çoğu zaman jQuery ile yazılırdı. Oysa jQuery rastgele sayı üretmez; yalnızca düğme ve metin işlemlerini kolaylaştırır. Bugün aynı iş ek kütüphane olmadan yapılabilir:
<button type="button" id="uret">Şifre üret</button>
<output id="sonuc"></output>
<script>
// guvenliSayi ve gucluSifre fonksiyonlarını buraya ekleyin
document.getElementById("uret").addEventListener("click", () => {
document.getElementById("sonuc").textContent = gucluSifre(16);
});
</script>
Sonucu innerHTML yerine textContent ile yazmak, şifredeki < veya & gibi karakterlerin HTML olarak yorumlanmasını önler. crypto.getRandomValues güvenli bağlam (HTTPS) gerektirmez ama sayfanızı yine de HTTPS üzerinden sunun.
Node.js'te şifre üretmek
Node.js'te en pratik yol node:crypto modülündeki randomInt fonksiyonudur. Aralığı kendisi sapmasız biçimde ayarladığı için reddetme örneklemesini sizin yazmanıza gerek kalmaz:
const { randomInt } = require("node:crypto");
function sifreUret(uzunluk = 16) {
const alfabe =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+?";
let sifre = "";
for (let i = 0; i < uzunluk; i++) {
sifre += alfabe[randomInt(alfabe.length)]; // 0 ile alfabe.length-1 arası
}
return sifre;
}
console.log(sifreUret(20));
Örnek çıktı (her çalıştırmada farklı olur):
_3tL8*!49qvBP6fZ^)kT
Tarayıcıyla aynı kodu paylaşmak isterseniz Node.js 19 ve sonraki sürümlerde global crypto.getRandomValues doğrudan çalışır; yukarıdaki tarayıcı örneği Node.js 24'te değişiklik yapmadan denendi. Daha eski sürümlerde (Node.js 15 ve sonrası) aynı nesneye require("node:crypto").webcrypto ile ulaşabilirsiniz.
Şifre sıfırlama bağlantısı gibi token'lar için karakter karakter seçim yapmak yerine randomBytes(16).toString("base64url") veya toString("hex") kullanmak daha kısadır.
Sık yapılan hatalar
İnternetteki şifre üretici örneklerinin çoğu çalışır ama güvenli değildir. Kendi kodunuzu veya kopyaladığınız bir örneği şu hatalara karşı kontrol edin:
- Math.random kullanmak: En yaygın hatadır. Çıktı rastgele görünse de kriptografik olarak güvenli değildir.
- Mod alıp geçmek:
getRandomValueskullanıp sonucu doğrudan% havuz.lengthile küçültmek, özellikleUint8Arrayile belirgin bir sapma yaratır. YukarıdakiguvenliSayifonksiyonunu kullanın. - sort ile karıştırmak:
sort(() => Math.random() - 0.5)hem güvensiz hem de eşit dağılmayan bir karıştırma yapar. Fisher–Yates kullanın. - Kullanıcıya özel "tohum" eklemek: Tarih, saat veya kullanıcı adından türetilen değerler rastgelelik katmaz, tersine tahmin edilebilirlik ekler.
- UUID'yi şifre sanmak:
crypto.randomUUID()güvenli rastgelelik kullanır ama biçimi sabittir ve yalnızca onaltılık karakter içerir. Kimlik numarası için uygundur; kullanıcı şifresi için yukarıdaki fonksiyonlar daha uygundur.
Koddaki 0x100000000 sabiti 232'ye, yani Uint32Array içindeki bir sayının alabileceği farklı değer sayısına eşittir. Sınır bu sayının havuz boyutuna bölünebilen en büyük katı olarak hesaplandığı için, kabul edilen her değer havuza eşit sayıda düşer.
Dikkat edilmesi gerekenler
- Şifreyi konsola veya günlüğe yazmayın: Örneklerdeki
console.logyalnızca deneme içindir. - Sunucuda saklarken özetleyin: Kullanıcı şifrelerini düz metin veya hızlı hash'lerle değil, Argon2, bcrypt ya da scrypt ile saklayın. Ayrıntılar şifre saklama yazısında.
- Uzunluk önemlidir: 77 karakterlik havuzdan 16 karakter yaklaşık 100 bit entropi verir. Uzunluğun etkisini şifre kaç karakter olmalı yazısında görebilirsiniz.
Aynı mantığın Python karşılığı için Python ile güvenli şifre üretme yazısına bakabilirsiniz; C#, Java ve PHP sürümleri de ayrı yazılarda.
Sık sorulan sorular
Math.random ile şifre üretmek neden güvensiz?
Math.random kriptografik güvenlik için tasarlanmamıştır ve belgeleri de bunu açıkça belirtir. Tarayıcılar hızlı ama öngörülebilir algoritmalar kullanır; yeterli çıktı gören biri sonraki değerleri tahmin edebilir. Şifre, token ve anahtar üretirken crypto.getRandomValues veya Node.js'te crypto.randomInt kullanın.
Modulo sapması (modulo bias) nedir?
Rastgele bir sayıyı karakter sayısına göre mod alarak küçülttüğünüzde, aralık karakter sayısına tam bölünmüyorsa bazı karakterler diğerlerinden daha sık çıkar. Örneğin 0–255 arası bir bayt 77 karakterlik havuza mod alınırsa ilk 25 karakter diğerlerinden daha olasıdır. Reddetme örneklemesi, bölünemeyen üst kısımdaki değerleri atıp yeniden çekerek bu sapmayı ortadan kaldırır.
JavaScript ile 10 karakterlik rastgele string nasıl üretilir?
Harf ve rakamlardan oluşan bir alfabe tanımlayın ve 10 kez, crypto.getRandomValues tabanlı sapmasız bir fonksiyonla bu alfabeden karakter seçin. Yazıdaki rastgeleString(10) fonksiyonu bunu yapar. Math.random().toString(36) kalıbı hem güvenli değildir hem de her zaman istediğiniz uzunlukta sonuç vermez.
Node.js'te hangi fonksiyonu kullanmalıyım?
Tek tek karakter seçmek için node:crypto modülündeki randomInt en pratik yoldur; sapmayı kendisi önler. Tarayıcıyla aynı kodu kullanmak isterseniz güncel Node.js sürümlerinde global crypto.getRandomValues da çalışır. Token gerekiyorsa randomBytes ile üretip base64url veya hex olarak kodlayabilirsiniz.
Tarayıcıda üretilen şifre sunucuya gider mi?
Kod tamamen tarayıcıda çalışıyorsa ve siz sonucu bir forma yazıp göndermiyorsanız hiçbir yere gitmez. Bu sitedeki şifre üretici de aynı yaklaşımı kullanır; şifreler tarayıcınızda üretilir ve sunucuya gönderilmez.



