Belgeler · Güvenlik
Açıklara kapalı.
Admin paneli sitenin anahtarıdır. Bu rehber en sık görülen saldırıları, nasıl çalıştıklarını ve bu depoda nasıl önlendiklerini anlatır.
01Tehdit tablosu
| Saldırı | Ne olur? | Önlem | Bu depoda |
|---|---|---|---|
| XSS | Saldırganın betiği admin tarayıcısında çalışır, oturum çalınır | Çıktıyı kaçır, CSP | e(), CSP script-src |
| SQL enjeksiyonu | Veritabanı okunur ya da silinir | Hazırlanmış sorgu, beyaz liste | PDO, EMULATE_PREPARES=false |
| CSRF | Admin farkında olmadan işlem yapar | Gizli token, SameSite çerez | csrf_field(), csrf_check() |
| Oturum çalma / sabitleme | Saldırgan admin gibi görünür | HttpOnly, Secure, yeniden üretim | session_regenerate_id(true) |
| Kaba kuvvet | Şifre denenerek bulunur | Hız sınırı, 2FA | login_attempts tablosu |
| IDOR | Başkasının kaydı adres değiştirilerek görülür | Her istekte yetki kontrolü | require_login($roles) |
| Clickjacking | Panel görünmez iframe içinde tıklatılır | frame-ancestors | X-Frame-Options: DENY |
| Dosya sızıntısı | .env, .git, yedekler indirilir | Erişimi engelle | .htaccess kuralları |
02HTTPS ve HSTS
Admin paneli HTTP üzerinden asla açılmamalı. .htaccess her isteği HTTPS’e yönlendirir; Strict-Transport-Security başlığı tarayıcıya bir yıl boyunca yalnızca HTTPS kullanmasını söyler.
03Güvenlik başlıkları ve CSP
| Başlık | Değer | Neyi engeller? |
|---|---|---|
Content-Security-Policy | yalnızca kendi alanın + CDN’ler | XSS, beklenmeyen betik ve stil |
X-Frame-Options | DENY | Clickjacking |
X-Content-Type-Options | nosniff | Tür tahminiyle betik çalıştırma |
Referrer-Policy | strict-origin-when-cross-origin | Adres sızıntısı |
Permissions-Policy | kamera, mikrofon, konum kapalı | İzinsiz cihaz erişimi |
Cross-Origin-Opener-Policy | same-origin | Pencereler arası saldırılar |
Tema betiği sayfa çizilmeden önce çalışmak zorunda olduğu için satır içidir; CSP onu hash ile tanır: 'sha256-CGGEJHfqC7+LiSARylTxPdCMaADvzU9UYiv/dnwTiYU='. Betiği değiştirirsen hash’i de güncelle.
04XSS: çıktıyı kaçır
<td><?= $row['name'] ?></td>
<td><?= e($row['name']) ?></td>Müşteri adına <script> yazan biri, sen siparişler sayfasını açtığında oturumunu çalabilir. Veritabanından, formdan ya da adresten gelen her metin ekrana e() ile basılır. JavaScript’te innerHTML yerine textContent kullan.
05SQL enjeksiyonu
$sql = "SELECT * FROM users WHERE email = '$email'";
$stmt = db()->prepare('SELECT id, password_hash FROM users WHERE email = ?');
$stmt->execute([$email]);Değerler her zaman parametredir. Sütun ya da sıralama yönü gibi parametre olamayan parçalar ise kendi beyaz listenden seçilir (DataTables uç noktasındaki $columns dizisi gibi).
06CSRF
Başka bir site, admin oturumu açıkken senin adına form gönderebilir. Her POST formu gizli bir token taşır; sunucu bu token’ı oturumdakiyle hash_equals ile karşılaştırır. Çerezdeki SameSite=Lax ek bir katmandır.
<form method="post" action="/api/kayit.php">
<?= csrf_field() ?>
</form>
csrf_check();07Oturum güvenliği
- Çerez
HttpOnly(JS okuyamaz),Secure(yalnızca HTTPS),SameSite=Lax. session.use_strict_mode=1: sunucunun üretmediği oturum kimliği kabul edilmez.- Girişte
session_regenerate_id(true): giriş öncesi kimlik çalınmışsa bile işe yaramaz. - Çıkış yalnızca POST ve CSRF ile; oturum ve çerez tamamen silinir.
- Ayarlar sayfasındaki “Aktif oturumlar” listesiyle diğer cihazlar kapatılabilir.
08Kaba kuvvet ve hız sınırı
Aynı IP ya da e-posta için 15 dakikada 5 hatalı denemeden sonra giriş kilitlenir. Hatalı denemelerde rastgele 200–400 ms beklenir; hata mesajı hangi alanın yanlış olduğunu söylemez.
if (too_many_attempts($email)) {
redirect_with('/giris/', 'Çok fazla deneme yapıldı. 15 dakika sonra tekrar dene.', 'danger');
}Daha güçlü koruma için Cloudflare’de /api/giris.php yoluna bir hız sınırı kuralı ekle.
09Şifre saklama ve 2FA
- Şifreler
password_hash(…, PASSWORD_DEFAULT)ile saklanır (bcrypt/argon2); MD5, SHA1 ya da düz metin asla. - Algoritma güçlendiğinde
password_needs_rehashile girişte otomatik yenilenir. - En az 10 karakter; kayıt ekranındaki güç göstergesi kullanıcıyı yönlendirir.
- Admin hesaplarında iki adımlı doğrulama (TOTP) zorunlu tutulmalı: doğrulama ekranı.
10Yetkilendirme ve IDOR
$user = require_login(['admin', 'editor']);
$stmt = db()->prepare('SELECT * FROM deals WHERE id = ? AND owner_id = ?');
$stmt->execute([$_GET['id'] ?? 0, $user['id']]);Bir butonu gizlemek güvenlik değildir. Her uç nokta kullanıcının rolünü ve kaydın ona ait olup olmadığını kendisi kontrol eder.
11Dosya yükleme
- Uzantıyı ve MIME türünü beyaz listeyle kontrol et (
finfo_file). - Dosyayı rastgele adla ve web kökünün dışına kaydet; asla kullanıcının verdiği adla değil.
- Boyutu sınırla (
upload_max_filesize,post_max_size). - Yükleme klasöründe PHP çalışmasını kapat:
php_flag engine off.
12.htaccess sertleştirme
Options -Indexes
RewriteRule (^|/)\. - [F,L]
RewriteRule ^ornekler(/|$) - [F,L]
<FilesMatch "\.(md|sql|log|ini|env|bak|sh|lock)$">
Require all denied
</FilesMatch><If "%{REQUEST_URI} =~ m#^/(ayarlar|siparisler)#">
Require ip 88.230.0.0/16 78.180.12.34
</If>AuthType Basic
AuthName "fkdev Admin"
AuthUserFile /var/www/.htpasswd
Require valid-user13Hata, log ve yedek
- Canlıda
display_errors=0; hatalarerror_logile dosyaya yazılır, kullanıcıya genel bir mesaj gösterilir. - Başarılı ve başarısız girişler
login_attemptstablosunda; olağandışı artışları izle. - Her gece veritabanı yedeği al, yedeği başka bir yerde sakla ve geri yüklemeyi gerçekten dene.
- PHP, MySQL ve sunucu paketlerini güncel tut; CDN dosyalarını sabit sürüm ve SRI ile kullan.