fkdev Adminv1.0.0

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?ÖnlemBu depoda
XSSSaldırganın betiği admin tarayıcısında çalışır, oturum çalınırÇıktıyı kaçır, CSPe(), CSP script-src
SQL enjeksiyonuVeritabanı okunur ya da silinirHazırlanmış sorgu, beyaz listePDO, EMULATE_PREPARES=false
CSRFAdmin farkında olmadan işlem yaparGizli token, SameSite çerezcsrf_field(), csrf_check()
Oturum çalma / sabitlemeSaldırgan admin gibi görünürHttpOnly, Secure, yeniden üretimsession_regenerate_id(true)
Kaba kuvvetŞifre denenerek bulunurHız sınırı, 2FAlogin_attempts tablosu
IDORBaşkasının kaydı adres değiştirilerek görülürHer istekte yetki kontrolürequire_login($roles)
ClickjackingPanel görünmez iframe içinde tıklatılırframe-ancestorsX-Frame-Options: DENY
Dosya sızıntısı.env, .git, yedekler indirilirEriş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ıkDeğerNeyi engeller?
Content-Security-Policyyalnızca kendi alanın + CDN’lerXSS, beklenmeyen betik ve stil
X-Frame-OptionsDENYClickjacking
X-Content-Type-OptionsnosniffTür tahminiyle betik çalıştırma
Referrer-Policystrict-origin-when-cross-originAdres sızıntısı
Permissions-Policykamera, mikrofon, konum kapalıİzinsiz cihaz erişimi
Cross-Origin-Opener-Policysame-originPencereler 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

PHPYanlış / doğru
<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

PHPYanlış / doğru
$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.

PHP
<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.

PHP
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_rehash ile 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

PHP
$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

.htaccess
Options -Indexes
RewriteRule (^|/)\. - [F,L]
RewriteRule ^ornekler(/|$) - [F,L]
<FilesMatch "\.(md|sql|log|ini|env|bak|sh|lock)$">
  Require all denied
</FilesMatch>
.htaccessİsteğe bağlı: paneli yalnızca belirli IP’lere aç
<If "%{REQUEST_URI} =~ m#^/(ayarlar|siparisler)#">
  Require ip 88.230.0.0/16 78.180.12.34
</If>
.htaccessİsteğe bağlı: giriş ekranından önce ikinci bir kapı
AuthType Basic
AuthName "fkdev Admin"
AuthUserFile /var/www/.htpasswd
Require valid-user

13Hata, log ve yedek

  • Canlıda display_errors=0; hatalar error_log ile dosyaya yazılır, kullanıcıya genel bir mesaj gösterilir.
  • Başarılı ve başarısız girişler login_attempts tablosunda; 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.

14Yayın öncesi kontrol listesi