Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!
[NODE JS] Crypto ile Rastgele Token Üretme
Merhaba arkadaşlar, bu yazıda Node.js crypto modülü ile güvenli rastgele token üretmeyi anlatacağım. E-posta doğrulama linkleri, şifre sıfırlama tokenları, API key'leri, session ID'leri... Hepsi güvenli rastgele değerler gerektirir. Math.random ile üretirseniz başınıza iş açarsınız, ciddi söylüyorum.
Math.random neden güvensiz diye soracaksınız. Çünkü Math.random kriptografik olarak güvenli değildir. Yani ürettiği sayılar tahmin edilebilir. Bir saldırgan belirli sayıda çıktıyı gözlemleyerek sonraki değeri tahmin edebilir. Token üretimi gibi güvenlik gerektiren işlerde bu kabul edilemez. crypto.randomBytes ise işletim sisteminin kriptografik rastgele sayı üretecini kullanır ve tahmin edilmesi pratikte imkansızdır.
Ben her projemde token üretimi için bir utility fonksiyonu yazarım ve projenin her yerinde onu kullanırım. Böylece tek noktadan yönetiyorum ve güvenli olduğundan eminim. Gelin nasıl yapıldığına bakalım.
Temel Token Üretme
JavaScript:
const crypto = require('crypto');
// Hex token (en yaygin)
function hexToken(byteUzunluk = 32) {
return crypto.randomBytes(byteUzunluk).toString('hex');
}
// URL-safe base64 token
function urlSafeToken(byteUzunluk = 32) {
return crypto.randomBytes(byteUzunluk)
.toString('base64url'); // Node 16+ base64url destekler
}
// Sayisal OTP (6 haneli)
function otpUret(haneSayisi = 6) {
const max = Math.pow(10, haneSayisi);
const randomBuffer = crypto.randomBytes(4);
const randomSayi = randomBuffer.readUInt32BE(0);
const otp = (randomSayi % max).toString().padStart(haneSayisi, '0');
return otp;
}
// UUID v4 benzeri
function uuidUret() {
return crypto.randomUUID(); // Node 19+
}
// Okunabilir token (insan dostu, buyuk harf ve rakam)
function okunabilirToken(uzunluk = 8) {
const karakterler = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // I,O,0,1 karistirma riski
const bytes = crypto.randomBytes(uzunluk);
let token = '';
for (let i = 0; i < uzunluk; i++) {
token += karakterler[bytes[i] % karakterler.length];
}
return token;
}
console.log('Hex token:', hexToken());
console.log('URL-safe:', urlSafeToken());
console.log('OTP:', otpUret());
console.log('UUID:', uuidUret());
console.log('Okunabilir:', okunabilirToken());
// Asenkron versiyon (non-blocking)
async function asyncToken(byteUzunluk = 32) {
return new Promise((resolve, reject) => {
crypto.randomBytes(byteUzunluk, (err, buffer) => {
if (err) reject(err);
else resolve(buffer.toString('hex'));
});
});
}
Burada birkaç farklı token tipi görüyorsunuz. Hex token en yaygın olanıdır, 32 byte ile 64 karakterlik bir string üretir. URL-safe base64 ise URL'de güvenle kullanılabilecek karakterler üretir, bu özellikle e-posta doğrulama linkleri için idealdir. OTP yani tek kullanımlık şifre ise SMS doğrulamaları için kullanılır.
Okunabilir token kısmında dikkat edin, ben I ile 1'i ve O ile 0'ı kasıtlı olarak çıkardım. Kullanıcılar bu karakterleri sürekli karıştırıyor, support ticket'larının yarısı bu yüzden açılıyordu bir projemde.
Pratik Kullanım: Şifre Sıfırlama Sistemi
JavaScript:
const crypto = require('crypto');
class TokenYonetici {
constructor() {
this.tokenSuresiDakika = 30;
}
// Sifre sifirlama tokeni olustur
sifreSifirlamaTokeni() {
const token = crypto.randomBytes(32).toString('hex');
// Token'in hash'ini DB'ye kaydet, token'in kendisini kullaniciya gonder
const tokenHash = crypto
.createHash('sha256')
.update(token)
.digest('hex');
return {
token: token, // Kullaniciya mail ile gonder
tokenHash: tokenHash, // DB'ye kaydet
sonGecerlilik: new Date(Date.now() + this.tokenSuresiDakika * 60 * 1000)
};
}
// Token dogrulama
tokenDogrula(gelenToken, dbTokenHash, sonGecerlilik) {
// Suresi gecmis mi?
if (new Date() > new Date(sonGecerlilik)) {
return { gecerli: false, sebep: 'Token suresi dolmus' };
}
// Hash'i kontrol et
const gelenHash = crypto
.createHash('sha256')
.update(gelenToken)
.digest('hex');
const eslesme = crypto.timingSafeEqual(
Buffer.from(gelenHash),
Buffer.from(dbTokenHash)
);
return {
gecerli: eslesme,
sebep: eslesme ? 'Gecerli' : 'Gecersiz token'
};
}
// API Key uretimi
apiKeyUret(prefix = 'sk') {
const key = crypto.randomBytes(24).toString('base64url');
return prefix + '_' + key; // sk_aBcDeFgHiJkLmNoPqRsTuV...
}
}
const yonetici = new TokenYonetici();
// Kullanim
const sifirlama = yonetici.sifreSifirlamaTokeni();
console.log('Kullaniciya gonder:', sifirlama.token);
console.log('DB ye kaydet:', sifirlama.tokenHash);
console.log('Son gecerlilik:', sifirlama.sonGecerlilik);
const apiKey = yonetici.apiKeyUret();
console.log('API Key:', apiKey);
Önemli Güvenlik Kuralları
Bir kaç kritik noktayı vurgulayayım. Token'i veritabanına kaydederken token'in kendisini değil, hash'ini kaydedin. Çünkü veritabanı sızıntısı olursa tüm tokenlar ele geçirilir. Hash'ini kaydederseniz saldırgan hash'ten orijinal token'ı bulamaz. Kullanıcı geldiğinde token'ı tekrar hashleyip veritabanındakiyle karşılaştırırsınız.
Ayrıca randomBytes'ın senkron versiyonu olan randomBytes yerine callback veya Promise versiyonunu tercih edin yoğun sunucularda. Senkron versiyon event loop'u bloklar. Ama düşük trafikli uygulamalarda senkron versiyon da sorunsuz çalışır, performans farkı microsaniye seviyesinde kalır.
Token uzunluğu konusunda da şunu söyleyeyim: en az 32 byte kullanın. 16 byte da güvenli sayılır ama 32 byte ile gönlünüz rahat etsin. 64 byte gereksiz uzun olur, URL'lerde sıkıntı çıkarabilir. 32 byte hex ile 64 karakter yapar, bu ideal bir uzunluk.
Kolay gelsin!
Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
- Cevaplar
- 3
- Görüntüleme
- 487
- Cevaplar
- 8
- Görüntüleme
- 709
- Cevaplar
- 3
- Görüntüleme
- 1K
