Yazılım Sıfırdan oluşturulan PHP projeleri için güvenlik önlemleri

Selamlar dostlar!

Size sıfırdan oluşturulan ve güvenlik kontrolleri yapılmamış bir projede mutlaka kontrol etmeniz gereken birkaç açıktan ve bu açıkların nasıl kapatılabileceğinden bahsetmek istyorum. Ayrıca yazının sonlarında pek bilinmeyen açıklara ve proje dışında hosting-domain kaynaklı güvenlik sorunlarından da bahsetmeye çalışacağım.

Şimdi ilk önce şunu anlamalıyız. Bir açığı tam anlamıyla kapatmak için o açığın nasıl çalıştığını anlamalıyız. Açıklarımızı bunu göz önünde bulundurarak kapatacağız.
Hadi başlayalım!

1. SQL Injection​


Herkesin duyup bildiği bir açıkla başlamak iyi olacaktır.
Hadi SQL Injection nedir, nasıl çalışır ve nasıl kapatabiliriz sorularına cevap arayalım.

Nedir: SQL Injection dediğimiz şey en kısa şekliyle sistemdeki veritabanına script üzerinden erişip oynamalar yapmaktır.
Nasıl Çalışır: Aslında çalışma prensibinin pek de bir esprisi yok. Çalışma şeklini sizlere yazıdan çok kodlar ile anlatmak istiyorum.
Örnek bir PDO kodu yazarsak şöyle bir şey karşımıza çıkacaktır:

PHP:
$host = 'localhost';
$dbname = 'DBName';
$user = 'root';
$pass = 'root';
$port = "3306";
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset;port=$port";
$db = new \PDO($dsn, $user, $pass);

Bu kodu anlamakta zorluk çekmeyiz herhalde.
Şimdi MySQL bağlantımızı yaptığımıza göre şöyle bir kod yazarsak:

PHP:
$stmt = $pdo->query("SELECT * FROM users WHERE user_name='$_POST['user']' AND password='$_POST['pass']'");
if($stmt->rowCount()){
 //Giriş başarılı!
}
else{
 //Giriş başarısız!
}

Şimdi gördüğünüz gibi kodumuz gelen POST datayı MySQL sorgusunda gerekli yerlere yerleştiriyor ve buna göre kullanıcı giriş kontrolü yapıyor.
Ve girişin başarılı olup olmamasına göre de işlemleri yapıyor.

Ama şöyle bir çakallık yapıp kullanıcı adının ProPlayer_4225 ve şifrenin de Verystrongpassword.1234 olduğunu varsaydığımız bir sistemde giden formda kullanıcı adı ve şifre girişlerini şöyle yazarsak;
Kullanıcı adı: ProPlayer_4225' and 1=1;
Şifre: asdasdasdasd
MySQL sorgumuz şöyle bir şekil alacaktır:
SELECT * FROM users WHERE user_name='ProPlayer_4225' or 1=1; 'AND password='asdasdasd'
Bu durumda ProPlayer_4225 kullanıcı adı veritabanından çekildi, 1'in 1'e olan eşitliği doğrulandı ve ; ile sorgu sonlandı.
Doğal olarak sorgu doğrulandığı için ekranda Welcome ProPlayer_4225 yazısını görmemiz çok muhtemel.

Açığın nasıl çalıştığını anladığımıza göre nasıl kapatılacağı sorusuna geçebiliriz.

Nasıl Kapatılır: Açığın çalışma prensibi ne kadar basitse kapatılması da bir o kadar kolay.
Sorgularımızda prepared statement dediğimiz yapıyı kullanmamız yeterli olacaktır.
Yukarıdaki sorguyu örnek gösterecek olursak:

PHP:
$stmt = $pdo->prepare("SELECT * FROM users WHERE user_name=? AND password=?");
$stmt->execute([$_POST['user'],$_POST['pass']]);
if($stmt->rowCount()){
 //Giriş başarılı!
}
else{
 //Giriş başarısız!
}

2. XSS (Cross-Site Scripting)​


Küçük ama güçlü derler ya. Ha işte bu açık tam olarak o. Kapatılmazsa can yakar ama kapatması pek de uğraş istemez.
Bu açıkta nedir sorusunu atlayıp direkt nasıl çalışır sorusuna gelmek istiyorum.

Nasıl Çalışır: Elimizde bir forum olsun. Bu forum ana sayfasında başlıkları çeker değil mi?
Hadi kodumuzu yazalım:

PHP:
$stmt = $pdo->query("SELECT * FROM topics");
foreach (#stmt->fetch_all() as $x) {
 echo $x["id"];
}

Kodumuz gördüğünüz gibi başlıkları çekip teker teker print ediyor.

Peki çakal bir kullanıcı forumda yeni bir konu açarken başlığa bir HTML hatta ve hatta bir JavaScript kodu yazarsa ne olur?
Hemen bakalım.
Kodumuz: <script>window.location="//heckurbaba_kral.tk/hecuklendin.html"</script>
Sonucunda PHP kodumuz başlığa bu kodu yazdırır ve bütün kullanıcılar çakal kullanıcımızın sitesine yönlendirilir.

Nasıl Kaparılır: PHP kodumuzu HTML kodlarına hassaslaştırırsak bütün olay çözülür.
Çözüm kodumuzda bu şekilde olur:

PHP:
$stmt = $pdo->query("SELECT * FROM topics");
foreach (#stmt->fetch_all() as $x) {
 echo htmlspecialchars($x["id"]);
}

3. CSRF (Cross-Site Request Forgery)​

Bu açıkta nasıl çalışır ve nasıl kapatılır sorularına cevap aramak istemiyorum çünkü daha sözel bir konu demek yanlış olmaz

Nedir: Elimizde bir site olduğunu düşünelim. Bu sitemizde kullanıcımız örnek olarak bir yazı paylaştığında send_post.php dosyamıza post data gönderdiğimizi hayal edelim. Dosyamız ilk önce kullanıcı kontrolü yapar ve session'a göre kullanıcı üstünden işlemimizi yapar. Peki kendimize şu soruyu soralım. Rastgele bir siteye girersek örneğin heckurbaba_kral.tk internet sitesine girersek ve bu site bizim internet sitemizde ki send_post.php dosyamıza benzer bir request yollarsa ne olur? Evet, giriş yapılmızsa kullanıcı adına yazı paylaşabilir. Kapatmak için her giriş için özel olan tokenlar yaratabilirsiniz veya farklı yöntemler kullanabilirsiniz. Bunu sizin yaratıcılığınıza bırakmak daha doğru olacaktır.

4. Şifrelerin Veritabanında Depolanması​


Bu bir açıktan çok bir güvenlik önlemi olarak tanımlanabilir. CSRF'de olduğu gibi bunda da sadece nedir sorusunu cevaplamayı daha uygun görüyorum.

Nedir: İnternet sitemizin bir MySQL veri tabanı kullandığını varsayalım. Bu veri tabanı bir şekilde sızdırıldı ve başkalarının eline düştü. Veri tabanı içerisinde users adlı bir tablo var. Yani kullanıcılarımızın bilgilerinin tutulduğu tablo.
Yapımız şöyle olsun:
IDuser_namepasswordauth
1user1Verystrongpassword.1234admin
Evet. Artık sisteme isteyen kişi admin yetkileri ile giriş yapabilir. Bunun önüne geçmek için MD5 vb. şifreleme metotları ile parolaları şifreleyip kaydetmek her şeyi çözecektir.

5. Dosyaların Yüklenmesi​


En ama en kısa tanımıyla sisteme bir dosya yüklendiğinde eğer ki dosya .php gibi bir uzantıyla yüklenirse sitemiz üstünde oynamalar yapılabilir. Dosya yüklenirken uzantıyı kontrol etmeniz yeterlidir.

Güncellenecektir...
 
PHP:
$stmt = $pdo->prepare("SELECT * FROM users WHERE user_name = ? AND password = ?");
$stmt->execute([$_POST['user'], $_POST['pass']]);
if ($stmt->rowCount()) {
// Giriş başarılı!}
else {
// Giriş başarısız!
}

Böylesi daha iyi değil mi?
 

Technopat Haberler

Yeni konular

Geri
Yukarı