Modern Web Uygulamalarında Teknik SEO: Kod Seviyesinde Kontrol Listesi
Core Web Vitals, canonical ve hreflang, render stratejisi ve yapısal veri: arama motorlarının sitenizi doğru anlaması için kod tarafında kontrol etmeniz gerekenler.
Hazırlanmış ifadeler, bağlama uygun çıktı kaçışı, Content Security Policy ve güvenli hata yönetimi: PHP projelerinde en yaygın iki saldırıya karşı uygulanabilir önlemler.
Enjeksiyon saldırıları yıllardır OWASP Top 10 listesinin üst sıralarında yer alıyor. İyi haber şu: SQL Injection ve XSS'in büyük bölümü, baştan doğru kurulmuş birkaç alışkanlıkla tamamen önlenebilir. Bu yazıda PHP projelerinde uyguladığım temel önlemleri kod örnekleriyle özetliyorum.
Sorun, kullanıcıdan gelen değerin SQL metnine string birleştirmeyle eklenmesidir:
// YANLIŞ: e-posta alanına ' OR '1'='1 yazılırsa sorgu değişir
$sql = "SELECT * FROM users WHERE email = '" . $_POST['email'] . "'";
Çözüm, hazırlanmış ifadeler (prepared statements) kullanmaktır. Sorgu ve veri veritabanına ayrı ayrı gider; veri hiçbir zaman komut olarak yorumlanmaz:
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
$stmt = $pdo->prepare('SELECT id, name FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();
Tablo adı, sütun adı veya sıralama yönü parametre olarak bağlanamaz. Bu değerleri kullanıcıdan alıyorsanız, yalnızca önceden tanımlı seçeneklerden birini kabul edin:
$allowed = ['created_at', 'price', 'title'];
$column = in_array($_GET['sort'] ?? '', $allowed, true) ? $_GET['sort'] : 'created_at';
$stmt = $pdo->query("SELECT * FROM listings ORDER BY $column DESC");
Ek olarak, uygulamanın veritabanı kullanıcısına yalnızca ihtiyaç duyduğu yetkileri verin; web uygulamasının tablo silme yetkisine sahip olması gerekmez.
XSS, kullanıcının girdiği bir içeriğin sayfada HTML veya JavaScript olarak çalışmasıdır. Temel kural: veriyi saklarken değil, ekrana yazarken ve yazdığınız bağlama uygun biçimde kaçışlayın.
function e(mixed $value): string
{
return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
?>
<h2><?= e($listing['title']) ?></h2>
<a href="/ilan/<?= e(rawurlencode($listing['slug'])) ?>">Detay</a>
ENT_QUOTES tek ve çift tırnağı da kaçışlar; öznitelik (attribute) içinde kullanım için şarttır.http ve https şemalarına izin verin; javascript: ile başlayan adresler kaçışlansa bile çalışır.json_encode ile JSON_HEX_TAG ve JSON_HEX_AMP bayraklarını kullanın.Blog editörü gibi HTML'e izin verilen alanlarda kaçış yapamazsınız; bunun yerine izin verilen etiket ve öznitelikleri beyaz listeyle sınırlayan bir temizleyici kullanın (ör. HTML Purifier). script, on* olay öznitelikleri ve style hiçbir zaman geçmemelidir.
Bir yerde kaçış unutulsa bile CSP, tarayıcının yalnızca izin verdiğiniz kaynaklardan betik çalıştırmasını sağlar. Satır içi betik kullanmayan bir sitede şu başlık güçlü bir başlangıçtır:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
base-uri 'self'; frame-ancestors 'none'; form-action 'self'
Oturum çerezlerini HttpOnly, Secure ve SameSite=Lax olarak işaretlemek, olası bir XSS'in oturum çalmaya dönüşmesini de zorlaştırır.
display_errors kapalı olsun; ayrıntılı hatalar sunucu günlüğüne yazılsın, kullanıcı yalnızca genel bir mesaj görsün. Dizin yolları ve tablo adları dışarı sızmamalı..env dosyasına yazılsın.composer audit bilinen açıkları listeler.SQL için hazırlanmış ifadeler ve beyaz liste; HTML için bağlama uygun kaçış ve temizleyici; tarayıcı için CSP ve güvenli çerezler. Bu üç katman birlikte uygulandığında, en yaygın saldırıların büyük bölümü daha kapıda durdurulur. Güvenlik sonradan eklenen bir özellik değil, ilk satırdan itibaren kodlama biçimidir.
Core Web Vitals, canonical ve hreflang, render stratejisi ve yapısal veri: arama motorlarının sitenizi doğru anlaması için kod tarafında kontrol etmeniz gerekenler.
İşletmeniz için doğru yazılımı seçmek; maliyet, veri sahipliği, entegrasyon ve büyüme planınıza bağlı. Karar vermeden önce yanıtlamanız gereken yedi soru.