Güvenlik & SSL

    Directory Traversal (Dizin Gezinme) Saldırısı Nedir?

    Dizin gezinme saldırısının hassas dosyalara nasıl ulaştığını ve girdi doğrulama ile korunmayı anlatan rehber.

    12 dk okuma Güncellendi: 10 Temmuz 2026

    Bir web uygulaması çoğu zaman dosyalarla çalışır: bir kullanıcı profil fotoğrafını görüntüler, bir rapor PDF'i indirir, bir dil dosyası yükler, bir şablonu ekrana basar. Bu işlemlerin neredeyse hepsinde uygulama, tarayıcıdan gelen bir metni alıp diskteki bir dosya yoluna çevirir. İşte tam bu çeviri anında, eğer gelen metin yeterince denetlenmiyorsa, saldırgan uygulamanın çalışması gereken klasörün dışına çıkıp sunucudaki bambaşka dosyalara ulaşabilir. Bu saldırı sınıfına directory traversal — Türkçesiyle dizin gezinme ya da yol gezinme (path traversal) — denir ve OWASP listelerinde onlarca yıldır yerini korumasının bir sebebi var: kavraması kolay, sömürmesi kolay, sonuçları ağır.

    Bu yazıda saldırının temel mekaniğini ../ dizilerinin ne işe yaradığından başlayarak somut örneklerle anlatacağız; /etc/passwd gibi klasik hedeflerin neden seçildiğine, LFI (Local File Inclusion) ile aradaki ince farka, kodlanmış (encode edilmiş) atlatma tekniklerine ve en önemlisi korunmanın dört ayağına — girdi doğrulama, kanonik yol kontrolü, en az yetkili çalıştırma ve dosya izinleri — kıdemli bir sistem yöneticisinin gözünden bakacağız.

    Directory Traversal Tam Olarak Nedir?#

    Directory traversal, bir uygulamanın kullanıcı girdisini bir dosya yoluna eklerken bu girdiyi yeterince doğrulamaması sonucu, saldırganın hedeflenen dizinin dışındaki dosyalara erişebilmesidir. Saldırının kalbinde işletim sistemlerinin dosya yolu sözdizimi yatar: . bulunulan dizini, .. ise bir üst dizini ifade eder. Bunu bir terminalde her gün kullanırsınız — cd .. komutu sizi bir klasör yukarı taşır. Saldırgan da tam olarak bunu yapar, sadece bir web isteğinin içine gömülü olarak.

    Diyelim ki bir uygulama, indirilecek dosyayı şöyle bir adresle belirliyor:

    https://ornek-site.com/indir?dosya=rapor-2026.pdf
    

    Arka planda sunucu muhtemelen şuna benzer bir mantık çalıştırıyor: sabit bir klasör alıyor (/var/www/uploads/), sonuna gelen dosya parametresini ekliyor ve sonucu okuyor. Eğer uygulama gelen değeri hiç denetlemeden birleştiriyorsa, saldırgan rapor-2026.pdf yerine şunu göndererek klasörden dışarı tırmanabilir:

    https://ornek-site.com/indir?dosya=../../../../etc/passwd
    

    Her ../ uygulamayı bir üst dizine taşır. Yeterince tekrarlandığında yol, dosya sisteminin kök dizinine (/) kadar çıkar; oradan etc/passwd'a inmek saldırganın istediği herhangi bir okunabilir dosyaya ulaşması anlamına gelir. Sonuçta uygulamanın diske gönderdiği gerçek yol şu hale gelir:

    /var/www/uploads/../../../../etc/passwd  →  /etc/passwd
    

    Buradaki kritik nokta, açığın uygulamanın ne kadar "akıllı" olduğuyla değil, girdiyi ne kadar denetlediğiyle ilgili olmasıdır. En modern framework bile, dosya yolunu ham kullanıcı girdisiyle elle birleştirdiğiniz anda bu açığa kapı aralar.

    ../ Dizileri Nasıl Çalışır: Adım Adım Örnek#

    Mekanizmayı somutlaştırmak için basit bir PHP örneği üzerinden gidelim — burada bilinçli olarak açık (savunmasız) kod yazıyoruz ki sorunun nerede olduğu net görülsün:

    <?php
    // SAVUNMASIZ — üretimde asla böyle yazmayın
    $dosya = $_GET['dosya'];
    $temel = '/var/www/uploads/';
    echo file_get_contents($temel . $dosya);
    

    Bu kod, dosya parametresini hiçbir kontrolden geçirmeden temel dizine ekliyor. Normal bir istekte (?dosya=fatura.pdf) her şey yolunda çalışır. Ama saldırgan şunu gönderdiğinde:

    ?dosya=../../../etc/passwd
    

    file_get_contents fonksiyonu /var/www/uploads/../../../etc/passwd yolunu çözer, .. dizileri onu yukarı taşır ve nihai olarak /etc/passwd dosyasının içeriği ekrana basılır. Linux'ta /etc/passwd her kullanıcı hesabının satırını içerir; tek başına parola içermese de sistemdeki kullanıcı adlarını, kabuk tercihlerini ve ev dizinlerini açık eder — bir sonraki saldırı adımı için altın değerinde bilgidir.

    Saldırganların gerçek hedefleri genellikle bundan çok daha değerlidir. İşte tipik bir hedef listesi:

    Hedef dosyaİçeriği / neden değerli
    /etc/passwdKullanıcı hesapları, kabuk ve ev dizini bilgisi
    /etc/shadowParola karmaları (yalnızca root okuyabilir)
    ../config/database.phpVeritabanı kullanıcı adı ve parolası
    ../.envAPI anahtarları, gizli anahtarlar, DB kimlik bilgileri
    /var/log/apache2/access.logLog zehirlemesiyle kod çalıştırma için
    ~/.ssh/id_rsaÖzel SSH anahtarı

    Dikkat edin: en tehlikeli hedefler /etc/passwd gibi sistem dosyaları değil, çoğu zaman uygulamanın kendi .env veya config dosyalarıdır. Bir saldırgan veritabanı parolanızı okuduğunda, dizin gezinme açığı bir anda tam bir veri ihlaline dönüşür.

    LFI ile İlişkisi: Okumaktan Çalıştırmaya#

    Directory traversal sıklıkla LFI (Local File Inclusion — Yerel Dosya Dahil Etme) ile birlikte anılır ve ikisi kavramsal olarak akrabadır, ama aralarında önemli bir fark vardır.

    • Saf directory traversal, hedef dosyayı okur ve içeriğini geri döndürür. file_get_contents, readfile, fopen gibi fonksiyonlar bu sınıfa girer. Sonuç: bilgi ifşası.
    • LFI, dosyayı okumakla kalmaz, onu uygulamanın koduna dahil eder ve çalıştırır. PHP'de include, require, include_once fonksiyonları bir dosyayı dahil ettiğinde, içindeki PHP kodu sunucuda yorumlanır.

    Farkı bir örnekle görelim. Şu savunmasız kod bir LFI açığıdır:

    <?php
    $sayfa = $_GET['sayfa'];
    include('/var/www/pages/' . $sayfa . '.php');
    

    Saldırgan burada sadece dosya okuyamaz; sunucuya PHP kodu çalıştırma kapısını aralar. Örneğin yükleme (upload) formuyla sunucuya masum görünen bir resim yükleyip içine PHP gömdüyse, o dosyayı include ile çağırdığında kod işletilir — bu artık uzaktan kod çalıştırma (RCE) demektir. Aynı şekilde web sunucusu access log'una bir kullanıcı ajanı (User-Agent) olarak PHP kodu enjekte edip ("log poisoning"), o log dosyasını dahil ettirerek de kod çalıştırılabilir.

    Özetle: directory traversal size bir dosyayı gösterir, LFI onu çalıştırabilir. Biri gizlilik ihlali, diğeri genellikle sistem ele geçirmesiyle sonuçlanır. İkisinin de kök nedeni aynıdır — kullanıcı girdisiyle bir dosya yolu kurmak. Bu tür saldırıları uygulamaya ulaşmadan uç katmanda süzen bir çözüm için web uygulama güvenlik duvarı (WAF) yazımıza göz atabilirsiniz; iyi ayarlanmış bir WAF, klasik ../ dizilerini ve LFI imzalarını istek daha kodunuza gelmeden reddeder.

    Filtreleri Atlatma Teknikleri: Neden "../ Yasak" Yetmez?#

    Çoğu geliştirici bu açığı ilk kez duyduğunda içgüdüsel olarak şunu yapar: gelen girdiden ../ dizilerini silmek. Ne yazık ki bu tek başına neredeyse hiçbir zaman yeterli olmaz, çünkü aynı yola ulaşmanın onlarca farklı yazımı vardır. Savunmayı doğru kurmak için saldırganın cephanesini bilmek gerekir.

    URL kodlaması (encoding). Sunucu isteği çözerken %2e%2e%2f dizisini ../ olarak yorumlar. Basit bir metin filtresi %2e içinde .. göremez:

    ?dosya=%2e%2e%2f%2e%2e%2fetc%2fpasswd
    

    Çift kodlama (double encoding). Bazı katmanlar girdiyi bir kez çözer; saldırgan iki kez kodlarsa (%252e%2e.) filtre atlatılabilir:

    ?dosya=%252e%252e%252fetc%252fpasswd
    

    İç içe yerleştirme. Filtre ../ dizisini bir kez ve tek geçişte siliyorsa, ....// yazımı silme işleminden sonra geriye ../ bırakır:

    ?dosya=....//....//etc/passwd
    

    Null byte (eski sistemler). Eski PHP sürümlerinde %00 karakteri yol dizesini sonlandırırdı; saldırgan eklenen .php uzantısını böyle atlatabiliyordu (?sayfa=../../etc/passwd%00). Güncel çalışma zamanlarında büyük ölçüde kapatılmıştır ama eski yığınlarda hâlâ karşılaşılır.

    Windows yol ayracı. Windows sunucularda ..\ ters bölü çizgisi de geçerlidir; yalnızca / filtreleyen bir kontrol bunu kaçırır.

    Bu tablonun anlattığı ders şudur: kara liste (yasaklı kalıpları silmek) yaklaşımı directory traversal'a karşı yapısal olarak zayıftır. Doğru savunma, "kötü olanı silmek" değil, "yalnızca iyi olana izin vermek" ve yolu diske dokunmadan önce mutlaklaştırıp (canonicalize) doğrulamaktır. Bir sonraki bölümlerde bunu inceliyoruz.

    Korunmanın Birinci Ayağı: Girdi Doğrulama ve Kanonik Yol Kontrolü#

    En etkili tek önlem, kullanıcı girdisini hiç yol olarak kullanmamaktır. Bunun en temiz yolu, kullanıcının bir dosya adı değil, bir kimlik (ID) göndermesini sağlamaktır. Uygulama bu ID'yi bir eşleme tablosunda gerçek dosya yoluna çevirir; kullanıcının ../ yazma şansı hiç doğmaz:

    <?php
    $izinli = [
        '1' => '/var/www/uploads/rapor-2026.pdf',
        '2' => '/var/www/uploads/fatura-ocak.pdf',
    ];
    $id = $_GET['id'] ?? '';
    if (!isset($izinli[$id])) {
        http_response_code(404);
        exit('Dosya bulunamadı');
    }
    readfile($izinli[$id]);
    

    Bu yaklaşım mümkün olmadığında — örneğin gerçekten dinamik bir dizinden dosya sunmanız gerekiyorsa — savunmanın altın kuralı kanonik yol kontrolüdür. Fikir şudur: girdiyi temel dizinle birleştir, ardından sonucu işletim sistemine mutlak, çözülmüş hâline getirt (tüm .. ve sembolik bağlar açılır), en sonda da bu çözülmüş yolun hâlâ izin verdiğin temel dizinin içinde olduğunu doğrula.

    PHP'de realpath() bu işi yapar:

    <?php
    $temel = '/var/www/uploads/';
    $istenen = $_GET['dosya'] ?? '';
    
    // Yolu çöz: .. ve semboller açılır, dosya yoksa false döner
    $tamYol = realpath($temel . $istenen);
    
    // Çözülen yol gerçekten temel dizinin içinde mi?
    if ($tamYol === false || strncmp($tamYol, realpath($temel) . '/', strlen(realpath($temel)) + 1) !== 0) {
        http_response_code(403);
        exit('Erişim reddedildi');
    }
    readfile($tamYol);
    

    Buradaki mantık kritik: realpath yolu fiziksel olarak çözer, yani ../../../etc/passwd girdisi verilse bile sonuç /etc/passwd olur — ve strncmp kontrolü bu yolun /var/www/uploads/ ile başlamadığını görüp isteği reddeder. Kodlama hilelerinin hiçbiri bu kontrolü atlatamaz, çünkü artık metnin nasıl yazıldığına değil, dosya sisteminin gösterdiği gerçek konuma bakıyoruz. Aynı desen diğer dillerde de vardır: Python'da os.path.realpath + os.path.commonpath, Node.js'te path.resolve + startsWith, Java'da getCanonicalPath().

    Ek olarak beyaz liste (allowlist) doğrulaması katmanlayın: dosya adının yalnızca beklenen karakterleri içermesini zorunlu kılın (örneğin ^[a-zA-Z0-9_-]+\.pdf$ gibi bir düzenli ifadeyle) ve /, \, : gibi ayraçlara hiç izin vermeyin.

    Korunmanın İkinci Ayağı: En Az Yetki ve Dosya İzinleri#

    Kod tarafındaki savunma birinci savunma hattıdır; ama güvenlik katmanlı düşünülür. Kodda bir açık kaçsa bile, sunucunun kendisi doğru yapılandırılmışsa saldırganın eline geçecek şey sınırlı kalır. Burada iki kavram öne çıkar: en az yetkiyle çalıştırma ve doğru dosya izinleri.

    Bir web sunucusu (Apache, Nginx-PHP-FPM) genellikle www-data gibi ayrıcalıksız bir kullanıcıyla çalışır — ve öyle çalışmalıdır. Bu kullanıcı root olmadığı sürece /etc/shadow gibi yalnızca root'un okuyabildiği dosyalara erişemez; directory traversal açığı olsa bile işletim sistemi izinleri saldırıyı sınırlar. Web sürecini asla root olarak çalıştırmayın.

    PHP tarafında open_basedir yönergesi, PHP'nin erişebileceği dizinleri kısıtlayan güçlü bir çittir. Bunu ayarladığınızda PHP, belirtilen dizin ağacının dışındaki hiçbir dosyaya — .. ile bile — ulaşamaz:

    ; php.ini veya sanal host yapılandırmasında
    open_basedir = /var/www/site/:/tmp/
    

    Bu satır devredeyken bir saldırgan ../../../etc/passwd gönderse dahi PHP dosyayı açmayı reddeder, çünkü hedef open_basedir ağacının dışındadır. Paylaşımlı hosting ortamlarında bu, hesapların birbirinden yalıtılmasının da temel taşıdır.

    Dosya izinlerini de sıkın. Web kök dizinindeki dosyalar için tipik güvenli değerler:

    # Dizinler: sahibi tam yetki, diğerleri yalnızca girebilir/listeleyemez mantığı
    find /var/www/site -type d -exec chmod 755 {} \;
    # Dosyalar: sahibi okuyup yazar, diğerleri yalnızca okur
    find /var/www/site -type f -exec chmod 644 {} \;
    # Gizli yapılandırma dosyaları: yalnızca sahibi okur
    chmod 600 /var/www/site/.env
    

    Özellikle .env, config.php, veritabanı yedekleri gibi hassas dosyaları web kök dizininin dışına taşımak en temiz çözümdür — mümkünse /var/www/site/config/ yerine /var/secure/ gibi web'den hiç servis edilmeyen bir yere koyun. İzin modelinin ayrıntıları için Linux dosya izinleri yazımız chmod ve sahiplik mantığını baştan sona anlatıyor. Bu kabuk komutlarını çalıştıracağınız kök (root) erişimi yalnızca VDS ya da sanal sunucu gibi yönetim yetkisi verdiğiniz planlarda bulunur; paylaşımlı hosting ortamlarında bu sertleştirmeler zaten sağlayıcı tarafından uygulanır.

    Web Sunucusu ve Uygulama Katmanında Ek Önlemler#

    Kod ve izinlerin yanında, web sunucusu yapılandırması da bir savunma katmanı sunar. Nginx tarafında hassas dosyalara doğrudan erişimi kesin bir kuralla engelleyebilirsiniz:

    # Nokta ile başlayan gizli dosyalara (.env, .git vb.) erişimi reddet
    location ~ /\. {
        deny all;
        return 404;
    }
    
    # Yalnızca beklenen uzantıları statik olarak sun
    location ~* \.(pdf|jpg|png|css|js)$ {
        root /var/www/site/public;
    }
    

    Bu, .git klasörünüzün veya .env dosyanızın yanlışlıkla servis edilmesini de önler — directory traversal olmasa bile bu dosyalar doğrudan URL ile istenerek sık sık sızdırılır.

    Uygulama katmanında ise dosya sunan tüm uç noktaları merkezî bir "güvenli dosya okuyucu" fonksiyonundan geçirmek çok işe yarar; böylece kanonik yol kontrolünü tek yerde yazar, her yerde kullanırsınız. Ayrıca dosya okuma isteklerini loglayın: kısa süre içinde çok sayıda ../ içeren istek gelmesi, aktif bir tarama işaretidir ve alarma bağlanabilir. Aşağıdaki tablo bu katmanları özetliyor:

    KatmanÖnlemNe durdurur
    GirdiID eşleme / allowlist regexHam yol girişini baştan keser
    Kodrealpath + temel dizin kontrolüTüm kodlama atlatmalarını
    Çalışma zamanıopen_basedir, ayrıcalıksız kullanıcıKaçan açığın etkisini sınırlar
    Dosya sistemi644/600 izinler, hassas dosyaları kök dışına alRoot-özel dosyalara erişimi
    Uç (edge)WAF + Nginx deny kurallarıİmza bilinen saldırıları kapıda

    Katmanlı savunmanın (defense in depth) özü budur: hiçbir katman tek başına kusursuz değildir, ama üst üste konduklarında saldırganın her birini aynı anda atlatması pratikte çok zorlaşır. Sitenizi kod tarafında sertleştirirken düzenli yedekleme almayı ve bir ihlal anında hızlı dönebilmek için site taşıma ya da geri yükleme yordamlarınızı hazır tutmayı da ihmal etmeyin.

    Sıkça Sorulan Sorular#

    Directory traversal ile LFI aynı şey midir?#

    Aynı kökten gelirler ama sonuçları farklıdır. Directory traversal, hedef dosyanın içeriğini okuyup geri döndürür ve genellikle bilgi ifşasıyla sonuçlanır; LFI ise dahil edilen dosyayı uygulama koduna karıştırıp çalıştırdığı için çoğu zaman uzaktan kod çalıştırmaya kadar gider. İkisinin de kök nedeni kullanıcı girdisiyle bir dosya yolu kurmaktır, dolayısıyla korunma yöntemleri büyük ölçüde ortaktır.

    Girdiden ../ dizilerini silmek yeterli bir savunma mıdır?#

    Hayır, ve bu en yaygın hatalardan biridir. Aynı yola URL kodlaması (%2e%2e%2f), çift kodlama (%252e), iç içe yazım (....//) ya da Windows'ta ters bölü çizgisi (..\) ile ulaşmanın onlarca yolu vardır. Kara liste yaklaşımı yapısal olarak zayıftır; doğru çözüm yolu realpath gibi bir fonksiyonla mutlaklaştırıp izin verilen temel dizinin içinde kalıp kalmadığını kontrol etmektir.

    Paylaşımlı hostingte bu açıktan etkilenir miyim?#

    Uygulama kodunuzda açık varsa evet, çünkü açık sizin yazdığınız betiğin girdiyi denetlememesinden kaynaklanır. Ancak ciddi paylaşımlı hosting sağlayıcıları open_basedir, CageFS gibi izolasyon katmanları ve sıkı dosya izinleriyle bir hesabın diğerine ya da sistem dosyalarına ulaşmasını büyük ölçüde engeller. Yine de bu katmanlar sizin uygulamanızın kendi .env dosyasını sızdırmasını önlemez, dolayısıyla kod tarafındaki doğrulama vazgeçilmezdir.

    WAF directory traversal'ı tek başına durdurur mu?#

    Bir WAF, bilinen ../ ve kodlanmış varyant imzalarını istek kodunuza ulaşmadan reddederek güçlü bir ön savunma sağlar, ama tek başına yeterli sayılmamalıdır. Yaratıcı kodlama teknikleri kural setini atlatabilir; asıl güvence uygulama kodundaki kanonik yol doğrulamasından gelir. WAF'ı en dış katman olarak düşünün, kod içi doğrulamayı ise son ve en sağlam savunma hattı olarak.

    Açığın sunucumda olup olmadığını nasıl test ederim?#

    Dosya adı ya da yol alan her uç noktayı manuel deneyerek başlayabilirsiniz; bir parametreye ../../../../etc/passwd ve kodlanmış eşdeğerlerini gönderip yanıtta kullanıcı listesi dönüp dönmediğine bakın. Daha sistematik bir tarama için OWASP ZAP, Burp Suite ya da açık kaynak dotdotpwn gibi araçlar bu payloadları otomatik dener. Testleri yalnızca sahibi olduğunuz ya da yazılı izniniz bulunan sistemlerde yapın; izinsiz test hukuki sorumluluk doğurur.

    Statik dosya sunan Nginx/Apache yapılandırmalarında da bu risk var mı?#

    Doğrudan disk yolu üreten dinamik kod olmadığı sürece klasik directory traversal riski düşüktür, çünkü web sunucusu root yönergesiyle sınırlı bir dizinden servis yapar. Ancak yanlış yapılandırılmış alias kuralları, .git/.env gibi dosyaların yanlışlıkla servise açılması ya da PHP'ye devredilen istekler yeni yollar açabilir. Bu yüzden nokta ile başlayan dosyalara erişimi deny all ile kapatmak ve yalnızca beklenen uzantıları sunmak iyi bir alışkanlıktır.

    Kapanış#

    Directory traversal, teknik olarak anlaşılması en kolay web açıklarından biridir ama tam da bu yüzden ihmal edildiğinde en pahalıya patlayanlardandır: birkaç ../ dizisi, denetimsiz bir dosya parametresini bir anda veritabanı parolanızın ya da SSH anahtarınızın sızdığı bir kapıya çevirebilir. İyi haber şu ki savunması da net: kullanıcıya asla ham dosya yolu kurdurmayın, yolları diske dokunmadan önce realpath ile mutlaklaştırıp temel dizin içinde kalıp kalmadığını doğrulayın, web sürecini en az yetkiyle çalıştırın ve hassas dosyaları doğru izinlerle web kök dizininin dışında tutun. Bu dört ayak üst üste konduğunda saldırgan için pratikte aşılmaz bir duvar oluşur.

    Bu sertleştirmeleri hayata geçirmek kök erişim ve doğru bir altyapı ister. Clou.TR olarak sunucu yönetimi hizmetimizle bu yapılandırmaları sizin için uygular; tam kontrol isteyenler için VDS ve sanal sunucu planlarımız, ek bir uç savunma katmanı için WAF ve DDoS koruma çözümlerimiz, WordPress siteleri için ise WordPress bakım paketlerimiz devrede. Sitenizi hangi katmanda sertleştirmek isterseniz isteyin, doğru başlangıç noktasını birlikte belirleyelim.

    GüvenlikWebOWASP

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.