Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 6

PHP ile Güvenlik

Öncelikle bu makaleyi, yeni başlayan veya orta düzey PHP programlayıcısına


hitap olması için gereken gayret gösterilmiştir. Orta düzey diyorum çünkü birçok kere
şahit olduğum üzere, PHP ile portal kodlayan ancak güvenlikten anlamayan çok
kişiye şahit oldum.
Bu makalede; Iframe virüsü, SQL Injection, RFI - LFI (Remote File Include -
Local File Include), XSS, CSRF ve SESSION ile scriptiniz nasıl güvenlikten mahrum
olur ve bunlardan nasıl kurtuluruz onu göreceğiz.
PHP ile kodladığınız scripte dışarıdan nasıl sızılır onu bir öğrenelim.

SQL INJECTION - Kurtulmak için gerekenler...


Mesela SQL Injection dediğimiz ve günümüzde en çok kullanılan metodu ele
alalım. Şimdi veritabanına bir query gönderiyoruz mesela ve diyelim ki basit bir login
işlemimiz ve bir query’miz olsun.

$name = $_POST['username'];
$pass = $_POST['pass'];
$sorgu = mysql_query("SELECT Count(id) FROM users WHERE name='$name' AN
D pass='$pass';");

Gördüğünüz gibi formdan gelen bilgileri direk olarak mySQL sorgusuna


ekledik ve isim ve şifreyi sorguladık. Ancak formdan gelen bilgiler süzülmediği için,
bazı ne idiğü belirsiz, hayat felsefesi insanlara zarar vermekten başka bir şey olmayan
hacker denilen art niyetli zararlı şahıslar;
Öncelikle forma şu bilgileri girerler; username alanına ' or 1=1 – girerler, pass
alanına ise asdasdasqweqweqwe gibi karakterler girerler. qweqweqwe gibi karakterler
girmelerinin sebebi, sizin formu gönderildikten sonra pass alanının boş olduğunda
hata verdirmenizden ötürüdür.
Şimdi bu şekilde girilen bilgiler olunca SQL sorgumuz ne hale geliyor bir ona
bakalım.

mysql_query("SELECT Count(id) FROM users WHERE name='' or 1=1 --' AND p


ass='asdasdasqweqweqwe'");

SQL’de -- karakterlerinden sonra gelen kısım, olduğu gibi açıklama olarak


kaldı. Yani 'AND pass='asdasdasqweqweqwe' kısmı, burada bildiğiniz açıklama
metni haline geldi ve bir işe yararlığı kalmadı.
Bu şekilde bir login durumu ile 1=1 ile direk olarak admin olarak login olmuş
oldu. Genelde 1. id numaralı satırda admin kayıtlıdır. O yüzden direk olarak admin
olarak login olmuş oldu. Bunun sebebi ise ' veya " karakteridir. Bu karakterler eğer
string olarak tanıtılmazsa, formdan gelen bilgiler otomatik olarak SQL sorgusuna
dönüşmüş oluyor. Bundan kurtulmak için ise yapmamız gereken şey çok basit.
Formdan gelen bilgileri escape ederek kurtulabiliriz ancak. Bu zararlıdan kurtulmak
için PHP dili bize bir avantaj olarak mysql_real_escape_string ve ya
mysql_escape_string fonksiyonlarını oluşturmuştur. Bu fonksiyonları kullanmak için
öncelikle veritabanı bağlantısı yapmanız lazım. Sonrasında ise, fonksiyonları
kullanabilirsiniz.
Örnek kullanım şekli şu haldedir.

$name = mysql_real_escape_string($_POST['username']);
$pass = mysql_real_escape_string($_POST['pass']);
$sorgu = mysql_query("SELECT Count(id) FROM users WHERE name='$name' AN
D pass='$pass';");

Şimdi bu fonksiyon ile süzülen veri, SQL sorgusuna nasıl yansır ona bakalım;

mysql_query("SELECT Count(id) FROM users WHERE name='\' or 1=1 --' AND


pass='asdasdasqweqweqwe'");

Gördüğünüz gibi ' ve " karakterleri hemen escape ediliyor. Yani \' \" şeklinde
kaydolduğu için, SQL sorgusu olmaktan çıkıp string olduğunu mySQL’e bildirmiş
oluyoruz. SQL Injection’dan kurtulduk mu peki bu kadarıyla? Tabii ki hayır.
Siz de bilirsiniz ki, SQL sorgularını sadece login’de kullanmıyoruz. O yüzden
önemli bir örneği vermeden geçemeyeceğim.
Şimdi escape fonksiyonumuzun ismine bir göz atalım.
mysql_real_escape_string(); Yani bu fonksiyon, sadece string türünü destekler.
Eee, bizler http://site.com/index.php?topic_no=12312312 olarak gelen integer
türündeki verileri nasıl süzeceğiz öyle ise? Bu da çok basittir. Ancak bu bilgiyi
atlarsanız, bütün DB bilgilerinizi çalarlar ama haberiniz olmaz.

$topic_no = $_GET['topic_no'];

Dersek, SQL sorgumuzda yine ' " gibi karakterlerle saldırıya uğrarız. O yüzden
doğrusu bu şekilde olmalıdır.

$topic_no = intval($_GET['topic_no']);
$topic_no = str_replace("-","",$topic_no);

Integer alanını sorgulayacağımız için intval ile integer validasyon etmiş


oluyoruz. Yani GET ile gelen verimiz "1231231231hebelehubele" ise, intval sayesinde
"1231231231" oluyor. Yani fonksiyonumuz ilk karakterden itibaren tek tek her
karakteri sona kadar inceliyor gelen veriyi ve eğer ilk karakter herhangi bir rakam ise,
yani 12313 gibi başlıyorsa, döngüye devam ediyor, ama asd gibi string türe denk
geliyorsa orada döngü break; olup sonlanıyor. Ve bize soldan itibaren aldığı rakamları
veriyor. Eğer ilk karakter string olsaydı, o zaman da döngüden geri gelen değer 0
oluyor. Veya başlarına - gibi karakterler koyarak, mySQL’de - integer türü id
incelemeye kalkıyor ve hata verdiriyor. O yüzden - karakterlerini de replace etmekte
fayda var, bu düşüncem yanlış ise düzeltin lütfen.
Sorgulama yapacaksanız eğer, muhakkak, COOKIE, SESSION, GET, POST ile
gelen verileri muhakkak escape etmelisiniz! COOKIE ve SESSION’da değiştirilebildiği
için onlardan gelen verileri de süzün yoksa hacklenmemenizi garanti edemem.
Peki, sadece SQL Injection'dan kurtularak sitenin hacklenmesini engellemiş
olduk mu? Tabii ki hayır.

RFI - LFI(Remote File Include - Local File Include) Açığından


Kurtulmak
RFI dediğimiz olayın açılımı, Remote File Include, tercümesi de Uzaktan
Dosya Eklemek olabilir. Bu olay, ilk olarak sunucunuzun SAFE MODE’un OFF
olmasından kaynaklanır. ON olsa bile OFF yapma oyunları mevcuttur tabi. Bu olayda
biz script kısmını ne kadar güvende tutsak bile, sunucunuzun güvenliği yine de ön
plana çıkıyor maalesef ve o yüzden yüksek güvenlikli bir sunucuya geçmenizi tavsiye
ederim her zaman.
Neden diye soracak olursak mesela bizim scriptimizde herhangi bir sorun yok
diyelim. Her yerini güvenli yaptık. Ama hacker denilen zat gelir, sisteme shell
sokuşturur. Shell dediğimiz zararlı kod ile sizin bütün dosyalarınızı ele geçirir, bu da
demektir ki, scriptiniz kendinize ait paralı bir script ise, bu scriptin çalınmasına
neden olur. Ayrıca Sql injection yapabilir. Dosya yükleyebilir. SQL yedeğinizi olduğu
gibi alabilir. Yani bir nevi Cpanel şeklinde bir kodlama diyebiliriz buna. Siz Cpanel’de
ne yapabiliyorsanız, aynısını hemen hemen shell’de görebilirsiniz. Tabi, suncuyu
hacklemek için kodlandığı için, sadece gerekli yerleri düzenlemek görmek amaçlı
yazılmıştır.
Adam gelir, config dosyanızı açar, içinde DB bilgilerinizi alır. DB bilgilerinizi
girerek mySQL alanınıza bağlanır. Sonra istediği tabloyu istediği gibi değiştirerek
yönlendirme kodu koyar. Alın size hacked. O yüzden, config dosyalarınızı da
saklamalısınız. Lamerlerden korunmak için config dosyanızın ismi config olmasın ve
içeriğini şifreleyin ve eval ile çalıştırın.
Mesela config dosyanızın içeriği şöyle olsun;

$ayar['db']['host'] = 'localhost';
$ayar['db']['name'] = 'veritabani_adi';
$ayar['db']['user'] = 'username';
$ayar['db']['pass'] = 'pass';

Adam böyle bir dosyayı açtığı gibi bilgiler eline hemen geçer. O yüzden
şifreleme metoduyla şifreleyin. Daha sonra da şifrelenmiş metni çözerek
eval($cozulmus_config_dosyası) deyince, yine aynı dosyanın içindekileri almış olur
ve PHP’ye o değişkenleri tanıtmış olursunuz.
Bu kısımları geçtikten sonra RFI nasıl yersiniz dersek, şöyle olabilir. Mesela
index sayfamızdan bütün sayfaları çağırıyoruz diyelim.

http://site.com/index.php?sayfa=Anasayfa
http://site.com/index.php?sayfa=Iletisim
http://site.com/index.php?sayfa=Forum
http://site.com/index.php?sayfa=Sikayet

şeklinde sayfalarımızı çağırarak hangi sayfayı include edeceğimizi bildiriyoruz. PHP


sayfamız da şöyle olsun.

$sayfa = $_GET['sayfa'];
include($sayfa . ".php");

Böyle bir kod ile biz GET ile gelen veriye ne yazarsak yazalım. Onu include
edecektir. Adam da gelir shell adresini oraya yazar ve shell yükler sunucunuza. Tabi
SAFE MODE kapalı ise hackler sitenizi. Doğrusu şöyle olmalı;

$sayfalar = array("Anasayfa" => "Anasayfa.php",


"Iletisim" => "Iletisim.php",
"Forum" => "Forum.php",
"Sikayet" => "Sikayet.php");
$sayfa = $_GET['sayfa'];
if(array_key_exists($sayfa,$sayfalar)){
include ($sayfalar[$sayfa]);
} else{
echo "Sayfa ismi hatalı, lütfen doğrusunu girin";
}
Veya switch, if gibi deyimler ile de kontrol edilebilir. Bu şekilde ne yaparlarsa
yapsınlar siz önceden belirttiğiniz ve programa kontrol koyduğunuz için RFI
yapamazlar.
Bunu da basitiyle anlatmış olduk. Daha da uzar gider aslında da sınırlı olarak
bırakıyorum.

XSS Enjekteden Kurtulmak


XSS (Cross Site Scripting - Çapraz Kod Çalıştırma) ise, HTML ve Javascript
yardımı ile siteyi yönlendirmek, sitede link vererek admin’in COOKIE bilgilerini
çalmak. Mesela GET ile bir ID alıyoruz şu şekilde;

http://site.com/index.php?cat_name=Belgesel

Ancak biz bu kategori ismini süzmeden alırsak şöyle olur.

http://site.com/index.php?cat_name=<script>alert(document.cookie)</script>

Böyle bir linke çeviririz. Siz de direk olarak süzmeden sayfaya bunu
yazdırırsanız, otomatik olarak sayfada bu Javascript kodu çalışacaktır. Veya diyelim
ki, bir yorum yazdıracaksınız. HTML verilerini muhakkak süzmeniz gerekmektedir.
Yoksa adam yorum yazarken;

<script>location='http://www.hebelehubele.com/index.php';</script>

Şu zararlı kodu da eklerse, o zaman yorumun yazıldığı sayfa her açılışında


muhakkak o adrese yönlenir. Bunlardan nasıl kurtuluruz dersek;

$veri = $_POST['comment'];//Yorumu posttan aldık.


$veri = strip_tags($veri);
$veri = htmlentities($veri);
$veri = htmlspecialchars($veri);

Bu fonksiyonlardan birini kullanabilirsiniz. Eğer strip_tags fonksiyonunu


kullanırsanız, POST’tan gelen verinin içinde, ne kadar HTML ve Javascript
karakterleri varsa siler. Sadece geriye kalan string türündeki veriyi alır. Bir ziyaretçi
defteri için en uygunu budur.
Ancak forum portalı veya blog tarzı ise, kişi HTML ve Javascript kodlarını
paylaşabileceği için, bu tagları silemezsiniz ama zararını da engellersiniz. Bunun için
htmlentities ve htmlspecialchars imdadınıza yetişir. Bu fonksiyonlar neredeyse aynı
işe yarar ama htmlspecialchars fonksiyonunda ek parametreler bildirebildiğiniz için
htmlspecialchars kullanmanız önerilir. Veriniz nereden gelirse gelsin, muhakkak
süzmeden almayın kaydetmeyin. Sonra başınız ağrımasın.
Başka bir yer daha var. BBCODE uygulamalarınızda da bu süzmeyi
yapmazsanız XSS yersiniz.

[url="javascript:alert(document.cookie);"]URL METNİ [/ url]


[img]javascript:location='http://google.com.tr';[/img]

Bu şekilde rahatça Javascript kodu çalıştırabilirsiniz. O yüzden bu verileri de


süzmek için str_replace kullanmanız gerekir. Ayrıca bir fonksiyonu görmedim ancak
sizin bir fonksiyon yazıp bu verileri süzmeniz lazım. Yoksa BBCODE ile çok rahat,
Javascript - HTML kodu çalıştırabilirler. Gördüğünüz gibi, hiç ummadığınız
yerlerden açık çıkabiliyormuş.
Mesela bir arama yapıyorsunuz. Aramanızda GET veya POST ile gelen metni
olduğu gibi ekrana bastırırsanız, XSS yemeniz, kaçınılmazdır.

SESSION Hack'den korunma


Diyelim ki, bir login sayfamız var ve biz bu sayfadan login olan kişilere
SESSION’da bir değer atadık diyelim.

$_SESSION['login'] = "1";
$_SESSION['tip'] = "admin";

Adam hangi sayfaya girerse girsin hiçbir sorgulama yapmaksızın direk olarak
adminliği ilan etmiş oluyor. SESSION değiştirilemez sanan arkadaşlar, SESSION’u
ben de değiştirilemeyeceğini sanıyordum ancak değiştirilebildiğini öğrendiğimden
beri, gözümde COOKIE kadar değeri kaldı. Bunu nasıl değiştirildiğine dair ufak
bilgilendirme yapacağım. Muhakkak süzmekte fayda var SESSION bilgilerini de.
SESSION değişmesi için öncelikle aynı sunucudan bir başka kullanıcının sizin
SESSION değerlerinizi bilmesi gerekir.

$_SESSION['login'] = '1';
$_SESSION['tip'] = 'admin';
header('Location: http://hackleneceksite.com/admin.php');

Bu işlemi yapmak için öncelikle karşı sitenin sizin SESSION değerlerinizi


bilmesi gerekir. Eğer aynı sunucuda olurlarsa SESSION değerleri yüzünden siteniz
hacklenir. O yüzden, SESSION yüzünden scriptiniz hacklenirse, hemen aynı
sunucuda olan bir başka kullanıcı sayesinde hacklendiğini bilmenizde fayda var.
SESSION’da bu tip uygulamaları yapmayın yaparsanız zararlı olursunuz.
Evet, arkadaşlar demek ki artık ne yapacakmışız? COOKIE, SESSION, GET,
POST gibi dışarıdan veri aldığımızda muhakkak ama muhakkak verileri süzecekmişiz.

IFRAME Virüsü ve Kurtuluşu


IFRAME virüsü nasıl bulaşır öncelikle ona bir göz atalım. Crack’li FTP
programlarından veya sunucunuza bulaşmış bir virüs ise sunucunuzdan sayfalarınıza
bulaşır.

• Nerelere bulaşır?
• index, home, main, default kelimeleri geçen tüm dosyalarınıza bulaşır.
• Kurtuluşu nedir?
• Crackli ftp programlarını kaldırın, FTP şifrenizi değiştirin, dosyalarınızın
içinde bulaşan kodları silin, Windows’un kendi FTP bağlantısını kullanın. Eğer
sorun çözülmezse format atın tekrar baştan itibaren aynı işlemleri yapın. Yine
sorun çözülmezse hosting sağlayıcınızla görüşün ve onlar çözsünler
sorununuzu.

Bu sorun genelde cuteFTP tipi crackli veya normal FTP programlarından


bulaşır. O yüzden korunmak için bu tür programları kullanmayın.
Bir de CSRF(Cross Site Request Forgery) vardır hack yöntemi ancak, şu
dönemde CSRF yiyen scriptler kaldığını zannetmem. Kalsa bile çok eski
scriptlerdendir yiyenler. Bu açık da, mesela bir html sayfası oluşturdunuz diyelim.
Şöyle diyelim;

http://hackleneceksite.com/my_profil...=profiledelete

gibi bir adresimiz olsun ve bu adreste post edilen bilgiler;

http://hackleneceksite.com/my_profil...te&submit=true

adresine yönlendirilsin. Sayfa içinde de

<input type="text" name="email">


<input type="hidden" name="username" value="üyeadı">
<input type="hidden" name="check" value="true">

böyle birer input olsun. Bu adreste siteden memnun değil isek sitenin bize tanıdığı bir
hak olsun profilimizi silmek için. Burada posttan gelen check true ise ve email
girilmiş ise, hemen profili silme işlemine geçiyor diyelim. O zaman biz de bir form
oluşturalım bir html sayfasında şu şekilde;
Biz eğer kullanıcının bilgilerinden emailini biliyorsak;

<form name='hack' action='http://hackleneceksite.com/my_profile.php?do=


profiledelete&submit=true' method='post'>
<input type="text" name="email" value="email@email.com">
<input type="hidden" name="username" value="üyeadı">
<input type="hidden" name="check" value="true">
</form>
<script>document.hack.submit();</script>

Şeklinde oluşturduğumuz html sayfasını kaydedelim ve tarayıcıda çalıştıralım.


Çalışınca ne olur derseniz, tabi ki profil silinir çünkü gördüğünüz gibi, profil
bilgilerini posttan alıyor. Tabi bunu ben sadece bir örnek olarak verdim, daha da
açılabilir bu örnek tabi ki...
Mesela phpbb için eski bir CSRF PM silme açığı;

<form action="http://[site]/phpBB2/privmsg.php?folder=inbox" method="post"


name="hack">
<input type="hidden" name="mode" value="" />
<input type="hidden" name="deleteall" value="true" />
<input type="hidden" name="confirm" value="Yes">
</form>
<script>document.hack.submit();</script>

Tabi bunlardan kurtulmak için muhakkak kendiniz, COOKIE veya SESSION


ile name ve pass ekleyip oradan verileri SQL de sorgulatmanız gerekmektedir. Yoksa
böyle basit işlem hataları yüzünden scriptinizde hasar ciddi olabilir. Ve geri
dönülemez de olabilir.

You might also like