Kısaca cevap
C# rastgele şifre oluşturma işinde System.Random yerine System.Security.Cryptography altındaki RandomNumberGenerator sınıfını kullanın. .NET 8 ve sonrasında tek satır yeterlidir: RandomNumberGenerator.GetString(alfabe, 16). Daha eski sürümlerde RandomNumberGenerator.GetInt32 ile karakter karakter seçim yapın. Aşağıdaki tüm kodlar .NET 10 ile çalıştırılarak denendi.
Bu sayfada
C# Random ile şifre üretmek neden güvensiz?
System.Random oyun, simülasyon ve test verisi için tasarlanmıştır. Hızlıdır ama kriptografik olarak güvenli değildir: aynı başlangıç değeriyle (seed) oluşturulan iki nesne aynı sayı dizisini üretir. Microsoft belgeleri de rastgele şifre gibi güvenli değerler için RandomNumberGenerator sınıfının statik metotlarını önerir.
var a = new Random(2026);
var b = new Random(2026);
Console.WriteLine(string.Join(", ", Enumerable.Range(0, 8).Select(_ => a.Next(10))));
Console.WriteLine(string.Join(", ", Enumerable.Range(0, 8).Select(_ => b.Next(10))));
1, 2, 9, 9, 9, 0, 6, 8
1, 2, 9, 9, 9, 0, 6, 8
İki satır birebir aynıdır. Test yazarken işe yarayan bu özellik, şifre üretirken ciddi bir açıktır. RandomNumberGenerator ise işletim sisteminin kriptografik rastgele sayı kaynağını kullanır; ona tohum veremezsiniz ve çıktısı tahmin edilemez. Konunun teorisi için kriptografi ve rastgelelik yazısına bakabilirsiniz.
Random ile RandomNumberGenerator farkı nedir?
| Özellik | System.Random | RandomNumberGenerator |
|---|---|---|
| Amaç | Oyun, simülasyon, test verisi | Şifre, token, anahtar, doğrulama kodu |
| Tohum verilebilir mi? | Evet; aynı tohum aynı diziyi verir | Hayır |
| Çıktı tahmin edilebilir mi? | Evet, güvenlik için tasarlanmamıştır | Hayır |
| Tamsayı | Next(max), Random.Shared.Next(1, 7) | GetInt32(max), GetInt32(min, max) |
| Hazır string / karıştırma | Güvenli değil; şifre için kullanmayın | GetString, GetItems, Shuffle (.NET 8+) |
Kural basit: tahmin edilmemesi gereken her değer için RandomNumberGenerator, geri kalan her şey için Random.
C# rastgele şifre oluşturma: GetString ile tek satır
.NET 8 ile gelen GetString, verdiğiniz karakter havuzundan istediğiniz uzunlukta bir string üretir. Harf, rakam ve 15 özel karakterden oluşan 77 karakterlik bir havuzla:
using System.Security.Cryptography;
const string Alfabe =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+?";
string SifreUret(int uzunluk = 16) => RandomNumberGenerator.GetString(Alfabe, uzunluk);
Console.WriteLine(SifreUret());
Console.WriteLine(SifreUret(24));
Örnek çıktı (her çalıştırmada farklı olur):
b_z-vmg@F)K!5T7U
B%Q1C$V07Zhplchfuz-)!m_t
77 karakterlik havuzdan seçilen 16 karakter yaklaşık 100 bit rastgelelik (entropi) verir. Uzunluğun etkisini şifre kaç karakter olmalı yazısında karşılaştırmalı görebilirsiniz.
Eski .NET sürümleri için GetInt32 döngüsü
GetString yoksa aynı işi .NET Core 3.0'dan beri bulunan GetInt32 ile yapabilirsiniz:
using System.Security.Cryptography;
using System.Text;
Console.WriteLine(SifreUret());
Console.WriteLine(SifreUret(24));
static string SifreUret(int uzunluk = 16)
{
const string alfabe =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+?";
var sb = new StringBuilder(uzunluk);
for (int i = 0; i < uzunluk; i++)
{
sb.Append(alfabe[RandomNumberGenerator.GetInt32(alfabe.Length)]);
}
return sb.ToString();
}
Örnek çıktı (her çalıştırmada farklı olur):
Xh!3lIa9=NDz2X!*
#fGct0RukkQIQ2zBHk*BeFS$
Modulo sapması: neden bayt % uzunluk yazmamalı?
Eski örneklerde rastgele baytlar üretilip bayt % alfabe.Length ile karaktere çevrildiği görülür. 0–255 arası bir bayt 77 karakterlik havuza bölünmez: 256 = 3 × 77 + 25 olduğu için ilk 25 karakter 256'da 4, diğerleri 256'da 3 olasılıkla seçilir. Bu dengesizliğe modulo sapması denir.
GetInt32 bu sorunu kendisi çözer. Microsoft belgelerine göre metot, basit mod almanın yaratacağı sapmayı önlemek için aralığa sığmayan değerleri atıp yeniden çeker. GetString ve GetItems de seçimi aynı güvenli kaynaktan yapar; 77 karakterlik havuzla 770.000 karakter ürettiğimizde her karakter yaklaşık 10.000 kez çıktı. Kendi dönüşümünüzü yazmak yerine bu hazır metotları kullanın.
Her karakter türünü garanti eden sürüm
"En az bir büyük harf, bir rakam ve bir özel karakter" isteyen siteler için önce her gruptan bir karakter seçin, kalanını tüm havuzdan doldurun ve sonra sırayı karıştırın:
using System.Security.Cryptography;
for (int i = 0; i < 3; i++) Console.WriteLine(GucluSifre(16));
static string GucluSifre(int uzunluk = 16)
{
string[] gruplar =
{
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"!@#$%^&*()-_=+?",
};
if (uzunluk < gruplar.Length)
throw new ArgumentOutOfRangeException(nameof(uzunluk), $"En az {gruplar.Length} olmalı");
string tum = string.Concat(gruplar);
char[] sifre = new char[uzunluk];
// Her gruptan en az bir karakter
for (int i = 0; i < gruplar.Length; i++)
sifre[i] = gruplar[i][RandomNumberGenerator.GetInt32(gruplar[i].Length)];
// Kalan konumlar tüm havuzdan
RandomNumberGenerator.GetItems<char>(tum, sifre.AsSpan(gruplar.Length));
// Sırayı güvenli biçimde karıştır
RandomNumberGenerator.Shuffle(sifre.AsSpan());
return new string(sifre);
}
Örnek çıktı (her çalıştırmada farklı olur):
O0==05Uxajv+dL-)
3)fRz#14MkSaK5g?
#hlQH7AH7P6L!O#^
Son adım önemlidir: karıştırmazsanız ilk dört karakter her zaman küçük harf, büyük harf, rakam ve özel karakter sırasıyla gelir. RandomNumberGenerator.Shuffle bu işi kriptografik rastgelelikle yapar. Fonksiyonu 4 karakter uzunluğunda 10.000 kez çalıştırdık; her çıktıda dört türün de bulunduğunu, rakamın dört konuma da yaklaşık eşit dağıldığını doğruladık.
C# random string generator: belirli uzunlukta string ve token
Her zaman şifre gerekmez. Davet kodu, dosya adı veya API anahtarı gibi değerler için de aynı sınıf kullanılır:
using System.Security.Cryptography;
string kod = RandomNumberGenerator.GetString(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 10);
string token = RandomNumberGenerator.GetHexString(32, lowercase: true);
string b64 = Convert.ToBase64String(RandomNumberGenerator.GetBytes(16));
Console.WriteLine(kod);
Console.WriteLine(token);
Console.WriteLine(b64);
Örnek çıktı (her çalıştırmada farklı olur):
G2LIOURIk4
14d1415f2411d07f5afad31fce9548eb
LFO5Fq6oU62K9tjkeThhoQ==
İlk satır 10 karakterlik alfanümerik bir string'dir. GetHexString(32) 32 onaltılık karakter, yani 128 bitlik bir değer üretir. GetBytes(16) ise 16 rastgele bayt verir; Base64'e çevrildiğinde 24 karakter olur. Base64 çıktısındaki +, / ve = karakterleri adres satırında sorun çıkarabilir; bağlantı için hex biçimi daha rahattır. Benzersiz kimlik gerekiyorsa GUID oluşturucu sayfasına da bakabilirsiniz.
C# random kullanımı: sayı üretme ne zaman hangisiyle?
Rastgele sayı gereken her yerde kriptografik üreteç şart değildir. Zar atma, oyun ya da örnek veri için Random.Shared (.NET 6+) pratik ve iş parçacığı açısından güvenlidir. Doğrulama kodu gibi tahmin edilmemesi gereken sayılar için GetInt32 kullanın:
using System.Security.Cryptography;
int zar = Random.Shared.Next(1, 7); // 1–6 arası, oyun için
int kod = RandomNumberGenerator.GetInt32(0, 1_000_000); // 0–999999 arası, güvenli
Console.WriteLine($"Zar: {zar}");
Console.WriteLine($"Doğrulama kodu: {kod:D6}");
Örnek çıktı (her çalıştırmada farklı olur):
Zar: 5
Doğrulama kodu: 357618
İki metotta da üst sınır dahil değildir: Next(1, 7) 1 ile 6 arasında, GetInt32(0, 1_000_000) 0 ile 999.999 arasında bir sayı döndürür. D6 biçimi, küçük sayıların başına sıfır ekleyerek kodu her zaman 6 hane yapar.
C# rastgele şifreler: uzunluk ve havuz nasıl seçilir?
Rastgele üretilen bir şifrenin gücü iki şeye bağlıdır: havuzdaki karakter sayısı ve uzunluk. Entropi, uzunluk × log2(havuz boyutu) formülüyle hesaplanır. Aşağıdaki değerleri bu formülle hesapladık:
| Havuz | Uzunluk | Yaklaşık entropi |
|---|---|---|
| Harf + rakam (62) | 12 | 71,5 bit |
| Harf + rakam (62) | 16 | 95,3 bit |
| Harf + rakam + 15 özel karakter (77) | 12 | 75,2 bit |
| Harf + rakam + 15 özel karakter (77) | 16 | 100,3 bit |
| Harf + rakam + 15 özel karakter (77) | 20 | 125,3 bit |
Tablodan görüldüğü gibi özel karakter eklemek entropiyi biraz artırır, ama dört karakter uzatmak çok daha büyük fark yaratır. Özel karakter kabul etmeyen sistemlerde yalnızca harf ve rakamla 16–20 karakter kullanmak iyi bir çözümdür. Fonksiyonlarınızı bu yüzden uzunluğu parametre olarak alacak şekilde yazın ve varsayılanı 16'nın altına düşürmeyin.
Havuzdan 0/O veya l/1 gibi birbirine benzeyen karakterleri çıkarmak, şifrenin elle yazılacağı durumlarda hataları azaltır. Havuz küçüldüğü için entropi biraz düşer; bunu bir iki karakter uzunlukla telafi edebilirsiniz.
Sık yapılan hatalar
- Her çağrıda
new Random(): Güvenlik sorununu çözmez; yalnızca farklı bir öngörülebilir dizi başlatır. - Havuza boşluk veya belirsiz karakter koymak: Havuzdaki her karakter şifreye girebilir. Boşluk, tırnak veya ters bölü bazı formlarda ve yapılandırma dosyalarında sorun çıkarır; havuzu bilinçli seçin.
- Tarih veya saatten "tohum" türetmek: Bu değerler rastgele değildir, tahmin edilebilirliği artırır.
- Şifreyi günlüğe yazmak: Örneklerdeki
Console.WriteLineyalnızca deneme içindir.
Dikkat edilmesi gerekenler
Ürettiğiniz şifreleri sunucuda saklarken düz metin veya MD5/SHA-256 kullanmayın; tuzlu ve yavaş bir yöntem seçin. Ayrıntılar şifre saklama ve C# ile güvenli şifre hashleme yazılarında. MD5 ve SHA-256'nın C#'taki kullanımını C# ile MD5 ve SHA-256 hash hesaplama yazısında bulabilirsiniz.
Aynı yaklaşımın diğer dillerdeki karşılıkları: Python, JavaScript, Java ve PHP. Kod yazmadan hemen bir şifreye ihtiyacınız varsa şifre üretici tarayıcınızda çalışır ve ürettiği şifreyi hiçbir yere göndermez.
Sık sorulan sorular
C# Random sınıfıyla şifre üretmek neden güvensiz?
System.Random hızlı ama öngörülebilir bir sözde rastgele sayı üreteci kullanır. Aynı başlangıç değeriyle (seed) oluşturulan iki nesne birebir aynı sayıları verir. Microsoft belgeleri de rastgele şifre gibi kriptografik olarak güvenli değerler için RandomNumberGenerator sınıfının statik metotlarının kullanılmasını söyler.
RandomNumberGenerator.GetString hangi .NET sürümünde var?
GetString, GetItems, GetHexString ve Shuffle metotları .NET 8 ile geldi. GetInt32 ise .NET Core 3.0'dan beri vardır. .NET 8'den eski bir sürüm kullanıyorsanız yazıdaki GetInt32 döngüsü aynı işi güvenli biçimde yapar.
C# ile belirli uzunlukta random string nasıl üretilir?
Kullanmak istediğiniz karakterleri bir string olarak tanımlayın ve RandomNumberGenerator.GetString(karakterler, uzunluk) çağırın. Örneğin 10 karakterlik alfanümerik bir değer için harf ve rakamlardan oluşan 62 karakterlik havuzu ve 10 uzunluğunu verirsiniz. Onaltılık bir değer yeterliyse GetHexString daha kısadır.
Oyun veya test verisi için de RandomNumberGenerator kullanmalı mıyım?
Gerek yoktur. Zar, kart karıştırma veya örnek veri gibi güvenlikle ilgisi olmayan işlerde Random.Shared yeterli ve daha hızlıdır. Şifre, token, doğrulama kodu ve anahtar gibi tahmin edilmemesi gereken her değer için RandomNumberGenerator kullanın.
Ürettiğim şifreyi veritabanında nasıl saklamalıyım?
Kullanıcı şifrelerini düz metin olarak veya MD5, SHA-256 gibi hızlı özetlerle saklamayın. Tuz kullanan ve bilerek yavaş çalışan bir yöntem seçin; .NET'te yerleşik seçenek Rfc2898DeriveBytes.Pbkdf2'dir, Argon2 veya bcrypt için ise ayrı kütüphaneler bulunur.



