Bu ders için video bulunmamaktadır.
Ders İçeriği
Giriş: Güvenlik ve Performans Neden Önemli?
Modern web uygulamaları, kullanıcı verilerini işler, hassas bilgilere erişir ve sürekli olarak yüksek trafikle karşılaşır. Bu nedenle, uygulamaların hem güvenli hem de yüksek performanslı olması kritik öneme sahiptir. Güvenlik açıkları veri ihlallerine, itibar kaybına ve yasal sorunlara yol açabilirken, düşük performans kullanıcı deneyimini olumsuz etkiler ve iş kaybına neden olabilir.
Güvenlik Açıkları ve Önlemler
XSS (Cross-Site Scripting)
XSS, saldırganların web sayfalarına kötü amaçlı istemci tarafı betikleri (genellikle JavaScript) enjekte etmesine olanak tanıyan bir güvenlik açığıdır. Bu betikler, kullanıcı oturumlarını çalmak, web sitelerini tahrif etmek veya kullanıcıları kötü amaçlı sitelere yönlendirmek için kullanılabilir.
Önleme Yöntemleri:
- **Girdi Doğrulama (Input Validation):** Kullanıcıdan gelen tüm girdileri sunucu tarafında doğrulamak ve temizlemek.
- **Çıktı Kodlama (Output Encoding/Escaping):** Kullanıcı tarafından sağlanan verileri HTML içeriği olarak yorumlanmayacak şekilde kodlamak. Örneğin,
<
karakterini<
olarak değiştirmek. - **İçerik Güvenlik Politikası (Content Security Policy - CSP):** Tarayıcıya hangi kaynaklardan betik, stil ve diğer varlıkların yüklenebileceğini bildiren bir HTTP başlığı.
const express = require('express');
const app = express();
const escapeHtml = require('escape-html');
app.get('/search', (req, res) => {
const query = req.query.q;
// Kötü: res.send(`Arama sonucunuz: ${query}`);
// İyi: Çıktı kodlama ile XSS önleme
res.send(`Arama sonucunuz: ${escapeHtml(query)}`);
});
app.listen(3000, () => console.log('Uygulama 3000 portunda çalışıyor'));
CSRF (Cross-Site Request Forgery)
CSRF, saldırganın, kullanıcının kimliğini kullanarak kullanıcının bilgisi veya rızası olmadan bir web uygulamasına istenmeyen komutlar göndermesini sağlayan bir saldırı türüdür. Örneğin, bir kullanıcının banka hesabından para transferi yapmasını sağlamak.
Önleme Yöntemleri:
- **CSRF Tokenları:** Her form isteğine veya AJAX isteğine benzersiz, sunucu tarafından oluşturulan bir token eklemek. Sunucu, isteği işlerken bu tokenı doğrular.
- **SameSite Çerezleri:** Çerezlerin yalnızca aynı site isteğiyle gönderilmesini sağlayarak CSRF saldırılarını önlemeye yardımcı olur.
const express = require('express');
const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const app = express();
app.use(cookieParser());
app.use(csrf({ cookie: true }));
app.get('/form', (req, res) => {
res.send(`
<form action="/process" method="POST">
<input type="hidden" name="_csrf" value="${req.csrfToken()}">
<input type="text" name="item">
<button type="submit">Gönder</button>
</form>
`);
});
app.post('/process', (req, res) => {
res.send('İşlem başarılı!');
});
app.use((err, req, res, next) => {
if (err.code === 'EBADCSRFTOKEN') {
res.status(403).send('Geçersiz CSRF tokenı');
} else {
next(err);
}
});
app.listen(3000, () => console.log('Uygulama 3000 portunda çalışıyor'));
SQL Injection
SQL Injection, saldırganın bir uygulamanın veritabanına kötü amaçlı SQL kodları enjekte etmesine olanak tanıyan bir güvenlik açığıdır. Bu, hassas verilerin çalınmasına, değiştirilmesine veya silinmesine yol açabilir.
Önleme Yöntemleri:
- **Parametreli Sorgular (Prepared Statements):** SQL sorgularında kullanıcı girdilerini doğrudan birleştirmek yerine parametre olarak kullanmak. Bu, girdinin SQL kodu olarak yorumlanmasını engeller.
- **ORM/ODM Kullanımı:** Sequelize (SQL) veya Mongoose (MongoDB) gibi ORM/ODM kütüphaneleri, varsayılan olarak SQL Injection saldırılarına karşı koruma sağlar.
- **Girdi Doğrulama:** Kullanıcıdan gelen verileri düzenli ifadelerle veya kütüphanelerle doğrulamak.
const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const app = express();
app.use(express.json());
const db = new sqlite3.Database(':memory:');
db.serialize(() => {
db.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)");
db.run("INSERT INTO users (name, email) VALUES (?, ?)", "Alice", "alice@example.com");
});
app.get('/users', (req, res) => {
const userId = req.query.id;
// Kötü: db.all(`SELECT * FROM users WHERE id = ${userId}`, (err, rows) => { ... });
// İyi: Parametreli sorgu ile SQL Injection önleme
db.all(`SELECT * FROM users WHERE id = ?`, [userId], (err, rows) => {
if (err) {
res.status(500).send('Veritabanı hatası');
} else {
res.json(rows);
}
});
});
app.listen(3000, () => console.log('Uygulama 3000 portunda çalışıyor'));
Kimlik Doğrulama ve Yetkilendirme
Kimlik doğrulama (Authentication), bir kullanıcının kim olduğunu doğrulamak, yetkilendirme (Authorization) ise kullanıcının belirli bir kaynağa veya işleme erişim izni olup olmadığını belirlemektir.
Passport.js ile Kimlik Doğrulama
Passport.js, Node.js için esnek ve modüler bir kimlik doğrulama middleware'idir. Çeşitli kimlik doğrulama stratejilerini (yerel, Google, Facebook vb.) destekler.
npm install passport passport-local express-session
const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(session({
secret: 'gizli-anahtar',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(
(username, password, done) => {
// Gerçek uygulamada veritabanından kullanıcıyı kontrol edin
if (username === 'testuser' && password === 'password123') {
return done(null, { id: 1, username: 'testuser' });
} else {
return done(null, false, { message: 'Yanlış kullanıcı adı veya şifre.' });
}
}
));
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
// Gerçek uygulamada kullanıcıyı ID'ye göre veritabanından alın
done(null, { id: 1, username: 'testuser' });
});
app.post('/login', passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/login',
failureFlash: true
}));
app.get('/dashboard', (req, res) => {
if (req.isAuthenticated()) {
res.send(`Hoş geldiniz, ${req.user.username}!`);
} else {
res.redirect('/login');
}
});
app.get('/login', (req, res) => {
res.send('Giriş YapGiriş');
});
app.listen(3000, () => console.log('Uygulama 3000 portunda çalışıyor'));
Performans Optimizasyonu
Caching (Önbellekleme)
Önbellekleme, sık erişilen verileri veya hesaplama sonuçlarını geçici bir depolama alanında tutarak, gelecekteki isteklerde daha hızlı yanıt verilmesini sağlar. Bu, veritabanı sorgularını azaltır ve sunucu yükünü düşürür.
Önbellekleme Türleri:
- **Tarayıcı Önbellekleme:** HTTP başlıkları (Cache-Control, ETag) ile tarayıcının kaynakları önbelleğe almasını sağlamak.
- **Sunucu Tarafı Önbellekleme:** Redis veya Memcached gibi in-memory veritabanları kullanarak sık kullanılan verileri önbelleğe almak.
- **CDN (Content Delivery Network):** Statik varlıkları (resimler, CSS, JS) coğrafi olarak kullanıcılara daha yakın sunucularda önbelleğe almak.
const express = require('express');
const app = express();
const NodeCache = require('node-cache');
const myCache = new NodeCache({ stdTTL: 100, checkperiod: 120 }); // 100 saniye TTL
app.get('/data', (req, res) => {
const cacheKey = 'my_data';
const cachedData = myCache.get(cacheKey);
if (cachedData) {
console.log('Veri önbellekten alındı.');
return res.json(cachedData);
}
// Veritabanından veya başka bir kaynaktan veri al
const data = { id: 1, name: 'Örnek Veri', timestamp: new Date() };
myCache.set(cacheKey, data);
console.log('Veri önbelleğe alındı.');
res.json(data);
});
app.listen(3000, () => console.log('Uygulama 3000 portunda çalışıyor'));
Gzip Sıkıştırma
Gzip, HTTP yanıtlarının boyutunu küçülterek ağ trafiğini azaltır ve sayfa yükleme sürelerini hızlandırır. Express.js için compression
middleware'i kullanılabilir.
npm install compression
const express = require('express');
const compression = require('compression');
const app = express();
app.use(compression()); // Tüm yanıtlarda gzip sıkıştırmayı etkinleştir
app.get('/', (req, res) => {
res.send('Büyük bir metin içeriği...'.repeat(1000)); // Büyük bir yanıt simülasyonu
});
app.listen(3000, () => console.log('Uygulama 3000 portunda çalışıyor'));
Bellek Yönetimi ve Bellek Sızıntıları
Node.js, V8 JavaScript motoru sayesinde otomatik çöp toplama (Garbage Collection) özelliğine sahiptir. Ancak, yanlış kodlama pratikleri bellek sızıntılarına yol açabilir. Bellek sızıntıları, uygulamanın zamanla daha fazla bellek tüketmesine ve performans düşüşüne neden olur.
Yaygın Bellek Sızıntısı Nedenleri:
- **Kapanmayan Kapanışlar (Closures):** Dış kapsamdaki değişkenlere referans tutan fonksiyonlar, bu değişkenlerin çöp toplamasını engelleyebilir.
- **Global Değişkenler:** Gereksiz yere global kapsamda tutulan büyük objeler.
- **Zamanlayıcılar (Timers):** Temizlenmeyen
setInterval
veyasetTimeout
çağrıları. - **Olay Dinleyicileri (Event Listeners):** Kaldırılmayan olay dinleyicileri.
Bellek Sızıntılarını Tespit Etme:
- **Node.js Inspector:** Chrome Geliştirici Araçları ile bellek profili oluşturma.
- **
process.memoryUsage()
:** Uygulamanın anlık bellek kullanımını izlemek için. - **
heapdump
veyamemwatch-next
:** Bellek yığınını (heap) analiz etmek için kütüphaneler.
// Bellek sızıntısı örneği (kasıtlı)
let leakyArray = [];
setInterval(() => {
// Her saniye leakyArray'e yeni bir büyük obje ekleniyor
// Bu objeler hiçbir zaman temizlenmiyor, bellek sızıntısına yol açıyor
leakyArray.push(new Array(1000000).join('x'));
console.log('Bellek kullanımı:', process.memoryUsage().heapUsed / 1024 / 1024, 'MB');
}, 1000);
// Bu kodu gerçek bir uygulamada çalıştırmayın!
Pratik Alıştırma: Güvenli ve Optimize Edilmiş Uygulama
Mevcut bir Node.js uygulamasına (örneğin, önceki derslerde oluşturduğunuz bir API) aşağıdaki güvenlik ve performans iyileştirmelerini ekleyin:
- XSS saldırılarına karşı girdi doğrulama ve çıktı kodlama uygulayın.
- CSRF koruması ekleyin (formlar için).
- Veritabanı sorgularında parametreli sorgular kullanın (SQL Injection önlemek için).
- Basit bir önbellekleme mekanizması uygulayın (örneğin, sık erişilen veriler için).
- Gzip sıkıştırmayı etkinleştirin.
- Uygulamanızın bellek kullanımını izleyin ve olası sızıntıları tespit etmeye çalışın.