Modern Web Nasıl Çalışır?
Merhabalar, bu yazı Mehmet Dursun İnce’nin kendi Twitch kanalında yer alan Web Security 101 0x04 | Bir Hacker’ın Gözünden Modern Web Nasıl Çalışır ? isimli yayınını temel almaktadır.
Aşağıdaki gibi bir yerel ağımız olduğunu düşünelim. Bu yerel ağda ise bir adet modem ve iki adet de bilgisayar olsun.
Peki Pc-1 ilk açıldığı zaman ne olur?
Pc-1 ilk olarak bir DHCP Discover mesajı yayınlar. DHCP Discover mesajı, ağdaki DHCP sunucusu için “Ben buradayım, IP adresi ve diğer yapılandırma bilgilerini almak istiyorum” anlamına gelir. Sonrasında, DHCP sunucusu bu mesaja karşı, DHCP Offer yapar yani talep edilen bilgileri istemciye sağlar. Bu Discover mesajında olduğu gibi yine broadcast olarak yapılır. Buradaki DHCP işlerini yürüten ve yapılandırma bilgilerini istemcilere temin etmekle yükümlü olan cihaz modemdir. Fakat Pc-1 böyle bir mesaj yayınlamazsa modem, Pc-1'e gidip IP adresi ve diğer yapılandırma bilgilerini sağlayamaz.
Örneğimizde, yapılandırma bilgileri olan IP, Subnet Mask, DNS ve Gateway aşağıdaki gibi olsun. Bunların ne işe yaradığına daha sonra değineceğiz.
Modem(Gateway) IP’si 10.0.0.1 ve verdiği DNS 8.8.8.8 olsun,
Pc-1 IP’si 10.0.0.5,
Pc-2'nin IP’si ise 10.0.0.17 olsun.
ARP Protokolü
ARP, bir IP adresinin MAC adresiyle eşleştirilmesini sağlar. Yukarıdaki cihazların birbirleriyle IP adresi ile konuşmadan önce Layer 2'de yer alan protokol olan ARP ile birbirlerinin MAC adreslerini öğrenmeleri gerekiyor. Çünkü cihazlar birbirlerinin MAC adreslerini bilmeden iletişim kuramazlar. Yani Pc-1, Pc-2 ile konuşmak istediğinde Pc-2'nin MAC adresini bilmek zorunda. Bunu öğrenmek için broadcast mesajı yayınlaması gerekiyor.
Pc-1, broadcasti yayınlayıp Pc-2'nin MAC adresini öğrendikten sonra, bunu bir yere kaydetmesi gerekiyor ki bir daha görüşmek, konuşmak istediğinde tekrar broadcast mesajına ihtiyaç olmasın. Bu sebeple ARP tablosu adı verilen ve MAC adreslerini IP adresleriyle ilişkilendiren bu tabloda kayıtlar tutulur. Yani cihazlar birbirlerinin MAC adreslerini öğreniyor ve bunu kendi ARP tablolarına kaydediyor.
Anlatılanları daha net anlayabilmek için aşağıdaki görseli inceleyebilirsiniz.
Y=Pc1
X=Pc2
Z=Modem(Gateway)
Yukarıda da görüldüğü gibi 10.0.0.5 IP adresine sahip Pc-1'in sol tarafında PC-2 nin MAC adresini sembolize eden X ve Pc-2'nin ip adresi olan 10.0.0.17' yi görmekteyiz. Yani burada Pc-1 kendi ARP tablosuna, ‘X’ MAC adresi 10.0.0.17' ye ait diye kaydediyor. Hemen aşağısında aynı şekilde modem için de yaptığını görebilirsiniz. Yani modemin MAC adresi ‘Z’ ve IP adresi de 10.0.0.1'imiş.
Dikkat ederseniz bütün cihazların bunu kendi arp tablosuna aynı şekilde kaydettiğini görebilirsiniz.
Pc-1, Pc-2 ile konuşmak istediğinde Pc-2 ‘nin MAC adresini bilmesi gerektiğinden bahsettik. Kabaca Pc-1 ağ içinde” Ben 10.0.0.17 ile konuşmak istiyorum” diye bir broadcast mesajı yayınlar ve bu isteğe Pc-2 “Ben 10.0.0.17’yim X’te benim MAC adresim” diye cevap veririr ve böylece Pc-1, Pc-2 ile konuşmaya başlayabilir. Fakat kötü niyetli bir kişi bana “Ben Pc-2'yim al bu da MAC adresim” dediği zaman, herhangi bir doğrulama yapılmadan o kişi benim için Pc-2 olmuş oluveriyor. Çünkü ARP’ta Authentication mekanizması yok. Yani burada bir emin olamama durumu var. İşte Arp Poisingi, Arp Spoofing saldırıları buradan kaynaklanıyor.
ARP poisoning temelde, bir saldırganın ağdaki diğer cihazların ARP tablosunu manipüle ederek ağ trafiğini yönlendirmeye çalıştığı bir tür saldırıdır. Bu saldırı, genellikle ağ üzerindeki veri akışını izlemek, bilgi çalmak veya ağ trafiğini yönlendirmek için kullanılır. Bu saldırı, ARP protokolünün güvensiz doğasından kaynaklanır. Bu sebeple saldırganlar, ağdaki diğer cihazların ARP tablosunu manipüle ederek, kendi MAC adreslerini başka bir cihazın IP adresiyle ilişkilendirebilirler.
Mesela Pc-1, gidipte modeme 10.0.0.17'in MAC adresi artık X değil Y oldu derse. Modem artık Pc-2 ile yani 10.0.0.17 ile yaptığı tüm trafik iptal olur ve tüm trafik Pc-1 e gider. Bu durumda da modemin ARP tablosunda aynı MAC adresi 2 farklı adres için gözükmeye başlar. Aynı şekilde modemi de poising ederek ortaya giren Pc-1 ,Pc-2 HTTP ile x.com’a giderken bütün trafiği görebilir.
Yani, Pc-1 birinci poising ile modeme gidip “10.0.0.17' nin MAC adresi X değil Y oldu” dedikten sonra da Pc-2'yi de poising etmesi gerekecek. Pc-2'ye de gidip “Sen modemin MAC adresini Z olarak kaydettin fakat modemin MAC adresi değişti, onun MAC adresi artık Y oldu” diyecek.Böylece Pc-2 modem ile konuşmak istediği zaman Pc-1 e giderken modem Pc-2 ile konuşmak istediği zaman da yine Pc-1 e gidecek. Böylece Pc-2 internete çıktığı zaman internet trafiğini Pc-1 görebilir hale gelecek.
Şimdi internete çıkıp x.com’a gideceğiz fakat bunu yapılandırma bilgileri olmadan yapamayız. Bu bilgilerin bizim için neden önemli olduğuna kısaca bakalım.
GATEWAY
Gateway’in kelime anlamı geçiş kapısıdır. Şöyle düşünebilirsiniz,okulda Mehmet diye bir arkadaşınız var ve bu arkadaşınız yan sınıfta yer alamakta. Yan sınıfa gidebilmek için kendi bulunduğunuz sınıftan dışarı çıkmanız gerekir. İşte bu sınıf kapısı sizini için Gateway’dir. Yani biz kendi yerel ağımızdan internete çıkmak için bir geçiş kapısına ihtiyaç duyuyoruz.
SUBNET MASK
Peki Subnet Mask ne işe yarar?
Diyelim ki x.com 1.3.3.7 IP adresine sahip olsun. Şimdi bu IP adresinin yani x.com’un kendi yerel ağımda mı değil mi’yi anlamak için Subnete Mask’e ihtiyaç duyulur. Yani konuşmak istediğin cihazın benimle aynı ağda olup olmadığını anlamam için bir Subnete Mask değerine ihtiyacım var. Bu tam olarak doğru bir örnek olmasa da, daha iyi anlaşılması için Subnet Mask’i sınıf listesi olarak düşünebilirsiniz.
Şu ana kadar ki yaşanan şeyler Pc’yi açtığımızda yaşanılan şeyler, daha biz Google’a gitmeye başlamadık bile.
DNS
DNS , internet üzerindeki cihazların IP adreslerini insanlar tarafından anlaşılabilir alan adlarına dönüştürmek ve bu alan adlarından IP adreslerini bulmak için kullanılan bir sistemdir.
Bizim örneğimizdeki DNS sunucusu, Google’ın DNS sunucusudur ve verdiği DNS’de 8.8.8.8
Şimdi internete çıkmak için her şeye sahibiz. Fakat x.com’un IP adresini bilmiyoruz.
Peki ne yapacağız?
Google’a x.com yazıp enter’a bastığımız zaman, işletim sistemi ilk önce kendi hosts dosyasında böyle bir kayıt var mı diye bakar. Bunun sebebi hosts dosyasında sen daha DNS’e sormadan bir domainin bir IP adresiyle kendin ilişkilendirebiliyorsun. Yani işletim sistemi benim hosts dosyamda bu domain için bir IP adresiyle ilişkilendirme yapılıp yapılmadığını anlamak için bu dosyaya bakar.
Bu hosts dosyasını Linux etc/hosts de tutarken Windows ise system32/drivers/hosts pathinde tutar.
Eğer hosts dosyasında x.com’a dair bir kayıt yoksa işletim sistemi 8.8.8.8'e yani bizim Resolver Dns’imize x.com’un IP adresini sorar. Bunu yaparken de TCP ya da UDP protokolleri ile yapabilir fakat bu iş genelde UDP protokolü kullanılarak yapılır. Pc-1'in işletim sistemi, x.com’un IP’sini öğrenebilmek için 8.8.8.8'in 53 numaralı portuna bir UDP bağlantı talebinde bulunur.
53 numaralı port, DNS (Domain Name System) iletişimi için ayrılmıştır ve DNS sunucuları tarafından kullanılır.
Resolver DNS, x.com’un IP’sini bilmiyor ise Root DNS’e gider ve “Ben x.com’un IP’sini öğrenmek istiyorum,sen biliyor musun? ”diye sorar. Root Dns de “8.8.8.8, ben x.com’un kim olduğunu bilmiyorum ama sana bir DNS sunucusunun adresini vereceğim ,o x.com’un kim olduğunu biliyor git ona sor” diye cevap döner.
8.8.8.8 bu adrese yani TLD DNS’ine gider ve x.com’un IP adresini bilip bilmediğini sorar. Bu soru üzerine TLD DNS, Resolver DNS’e “Ben x.com’u bilmiyorum ama x.com’un kayıtlarını tutan DNS sunucusunun adresini biliyorum sen ona sor ”der ve biz de o adrese yani Autharitive Dns’e gideriz.
TLD DNS ’inin görevi *.com’ ları bilmek iken,
Autharitive Dns ise x.com’un dns sunucusudur.
İşte bu şekilde x.com’un IP’sinin 1.3.3.7 olduğunu öğreniriz. Dikkat ederseniz daha biz bu x.com ile iletişimde dahi bulunmadık.
Bunun karşılığı da dig ns hurriyet.com.tr bize bu sitenin tüm DNS kayıtlarının bilindiği DNS suncusunu görürüüz.
Böyle anlatınca biraz uzun gelebilir fakat bu neredeyse anlık olarak yaşanan bir süreçtir. Her ne kadar hızlı olsa da tekrar x.com’a gitmek istenildiği zaman aynı döngünün yaşanması oldukça gereksizdir. Bu sebeple DNS sunucusu yani 8.8.8.8 ,kendi cache’inde x.com’ un IP adresini tutar. Şayet bu DNS sunucusuna gelen başka bir cihaz için tekrar aynı süreç yaşanmaz, direkt olarak cevap verilir.
Bütün bunlar yaşanırken potansiyel tehlikelere de değinmek gerekiyor.
DNS sunucusunun tekrar aynı döngüyü yaşamaması için x.com’un IP adresini cache’inde tuttuğunu söylemiştik. Fakat bir saldırgan bu cache’i manipüle etmeyi başarabilirse 8.8.8.8'in verdiği cevapları da manipüle etmeyi başarabilir. Yani x.com’a gidecek olan tüm talepler başka bir IP adresine yönlendirilebilir.
Bununla birlikte Authoritative DNS sunucusunu ele geçirip MX, TXT kayıtları, CNAME ve A kayıtlarını kayıtlarını manipüle ederek kurumun maddi ve manevi kayıp yaşamasına sebep olunabilir.Hatta Tld’lere yapılan saldırılar sonucunda dünyadaki tüm *.com’ların cevapları sahte dönülebilir.
NAT (Network Address Translation)
Artık bizim bildiğimiz 1.3.3.7 IP’sine sahip bir sunucumuz var. Şimdi bizim Pc-1 bilgisayarı olarak, gatewayden çıkacak internetteki routerlardan geçecek ve 1.3.3.7'nin sunucusuna geleceğiz.
Peki tüm bunları hangi protokolü kullanarak yapacağız ve bu protokolün source ve destination Ip ve port değerleri ne olacak?
Bunu için TCP protokolünü kullanmamız gerekiyor. Çünkü TCP internette veri iletimi için kullanılan bir iletişim protokolüdür ve bu protokol UDP’nin aksine güvenilir ve connection based iletişim sağlar.
TCP Header’ınında birçok alan bulunur fakat şu an için dört tanesini ele alalım.
Source IP= 10.0.0.5 (Az sonra bu IP’ye NAT müdahale edip “Private Ip ile internete çıkamazsın “ diyerek bir public Ip ataması yapacak.)
Destination IP= 1.3.3.7
Soruce Port= 64357 //Source Port’unu işletim sistime random olarak seçer.
Destination Port= 80(x.com’un HTTP portu)
Source IP değeri olarak 10.0.0.5 olarak belirlenmiş olsa da bu şekilde Pc-1 internette gezemez. Çünkü bu IP’ler Private IP’leridir ve benim internete çıkabilmem için Public IP’ye ihtiyacım var. İşte bu Public IP’yi bana sağlayan yapı NAT’tir. NAT hizmetini bize sağlayan ise aynı zamanda gateway olan modemin kendisidir.
Buradaki NAT yani modem, giden paketin source ip değerini 10.0.0.5 yerine başka bir ip adresiyle değiştirmektedir. Bu da ortamdaki iki bilgisayarın da internete çıkarken aynı ip adresini kullandıkları anlamına gelir.Yani içeride farklı IP’ler olsa da internette gezinmeye başladığında aslında bütün cihazlar aynı IP ile dışarıya çıkıyor.Bunun sebebi de internete bağlı cihaz sayısı ile Ipv4 cihaz sayısı arasındaki uçurumdan dolayıdır.
TCP 3 Way Handshake:
TCP (Transmission Control Protocol), iki cihaz arasında güvenilir bir bağlantı kurmak için kullanılan bir protokoldür. Yani Pc-1 internete çıkıp, x.com’la iletişimi başlatmak için, birbirleri arasında farklı tipte TCP paketleri iletirler. Bu sürece 3lü el sıkışma denir. Bu sürecin var olmasının temel nedeni konuşulan kişiyi doğrulamak diyebiliriz.Mesela ben manuel ve random değer olarak Source ip kısmına 5.5.5.5 yazıp TCP datasını basıp gönderirisem x.com kendisiyle konuşan kişiyi 5.5.5.5 sanır ama 3.lü el sıkışmayı koyarsan Ip Spoofing’e engel oluşturmuş oluyorsun. Bu sürecin temelde 3 aşaması vardır.
Birinci adımda x.com’a bizden bir Syn (synchronize) paketi gider. Bu paket x.com ile iletişime geçmek istediğimizi iletir.
İkinci adımda ise x.com’dan bize “Benimle iletişime geçmek istediğini belirtmişsin iletişime geçebiliriz” anlamına gelen Syn+Ack paketini döner.
Son aşamada ise x.com’a “Pekala o zaman hadi konuşmaya başlayalım” anlamına gelen Ack(acknowledgment) paketini döneriz iletişim başlar.
Artık x.com’un 80 portu ile 3-Way Handshake’i tamamladık ve HTTP’ye çıkabiliriz. Http’nin yaptığı şey en temelde request alıp,response vermesidir.
Aklımızda şöyle canlandıralım, bir adet HTTP request’i göndermekteyiz ve buna karşılık bir response almaktayız. OSI Modelinde 7. katmanda iken bu şekilde sadece 2 tane paket varken, alt katmanlarda yüzlerce TCP paketi gidip gelmektedir. Bunu da görmenin en kolay yolu Wireshark’ı açarak trafiği izlemektir.
Web Sunucusuna Geldik
1.3.3.7'ye yani x.com’un sunucusuna artık gelebiliriz. 1.3.3.7 bir sunucu ama günümüzde Apache, Mysql ve Php gibi teknolojiler tek bir sunucunun içinde barındırılmıyor.
Her şeyden önce kurumun bir firewallı var. Yani sen x.com’un 80 portuna gittiğinde veya 3'lü el sıkışma gerçekleştireceğin zaman bu süreci firewall ile yaşarsın. Zaten firewall da temelde network managment işini yapar. Yani bu gelen adam bu portla, şu gelen adam ise şu portla konuşabilir ya da konuşamaz işini yapıyor.
Yani senin ilk temasa geçtiğin yer aslında firewalldır. Firewalldan sonra web sunucusuna ve DMZ’nin içindeki diğer yapılara gelirsin. Dmz’de yani sunucular bölgesi adamın yerel networküdür ve ARP gibi süreçler de aynı şekilde burada da yaşanır.
Firewall’ların işe yaradığı şeylerden bir tanesi de SYN Flood Attack gibi Ddos saldırılarına karşı da koruma kalkanı oluşturabilmesidir. Bu tarz bir saldırıda saldırgan, sunucuya TCP source’una random değerler yazarak TCP Syn paketi yollayarak gönderir. Bu durumda da web sunucunun bir süre sonra kaynağı tükenir. İşte bu yüzden de firewaller daha fazla güce sahip olur.
Virtual Hosting
Dünya genelinde kaç tane Ip adresi ve kaç tane domain olduğunu düşünecek olursak aradaki uçurumu görebiliriz. Bu yüzden tıpkı yerel ağda yaşanan NAT işlemi gibi web sunucuları da buna benzer bir olay yaşar. Buna Virtual Hosting(VHOST)denir.
Yani sunucuya hackerconf.stream/index’i bana getir diyorsan sunucu için bu dosya aslında sunucudaki “var/www/hackerconf.stream[dosya]” dosya içeriğine karşılık gelmekte.
XAMPP sunucusunu kurup sonra ilgili dizinin altında localhostta çalışmak gibi aslında.
Bu sayede dünyada birden fazla domain 15-20 tane domainin Ip adresi aynı olurken bir sunucu üzerinde farklı uygulamalar olarak bu şekilde çalışabiliyor. İşte buna virtual hosting deniliyor.
Daha ilkel dönemde genelde tek bir web sunucusu olurdu ve birçok şey bu sunucu üzerinde yer almaktaydı. Günümüzde ise artan internet kullanımına paralel olarak artan iş yükü ve karmaşık işlerin yapılmasının gereksinimi ile daha fazla sunucu, veritabanı eklemek ve sql proxy, load balancer(reverse proxy) gibi teknolojilerin kullanımı yaygınlaştı. Gelin bunların nedenlerine bakalım.
Buradaki yapıyı bir e-ticaret sitesi olarak düşünelim. Eğer tek bir web sunucusu olursa burada bazı problemler meydana gelebilmektedir. Örneğin Black Friday günlerinde çok fazla ziyaret ve satış yapıldığı için mevcut sunucu kendisi için yeterli olmamaktadır.
Eskiden ram eklemek veya sunucuyu başka bir yere taşımak bir çözüm olarak görülürdü. Günümüzde ise daha fazla web sunucusu kurmak ve bu sunucuların hepsine codebase’i ekleyerek yapılmakta.
Tek bir database yetmediği durumlarda ise daha fazla database kurmak ve bu veritabanlarını sunucudan ayırıp dışarıya koymak bir çözüm olarak yapılmaya başlandı.
Firewall aracılığıyla istemciden gelen istekleri web uygulamasına göndermek için ise reverse proxy ya da load balancer devreye girmeye başlıyor. Yani senin http requestin load balancer’a ya da reverse proxy’e geliyor ve bu sistem içerde müsait olan web sunucusuna aktarılıyor.
Şimdi gelen bu request, mesela 1 nolu sunucuya geldikten sonra, bu uygulamanın çalışırken oluşturduğu session, diskte tutuluyorsa, o adamın tüm requestlerde hep aynı yere gelmesi gerekecek. Çünkü session sadece 1 nolu sunucuda tutulmuş oluyor. Eğer 1 nolu web sunucu çökerse, adamı 2 no’lu sunucuya göndermek zorunda kalırız ki o zaman da logout yaşanır. Zamanla bu tarz sıkıntılar çıkamaya başlıyor. Peki ne olacak?
Buna çözüm olarak Cloudflare’ın cookie’si örnek olarak gösterilebilir. Reverse proxy, senden gelen requesti hangi sunucuya gönderdiğini bu cookieye bakarak anlıyor.Bu cookie kullanıcı ile reverse proxy arasında yani ileri tarafa hiçbir zaman geçmez. Reverse proxy cookie’ye bakarak diyor ki “ben bu adamı daha önce 1 nolu sunucuya yolladım şu bilgileri vardı ben yine bu kullanıcıyı 1 nolu sunucuya yollayayım” diyor. Buradan da anlaşılacağı üzere reverse proxy bu süreci cookie kullanarak yürütebilir.
Sunucuyu bir kenara bırakalım, bu sefer de tek bir tane database yetmediği durumlar için birden fazla database kurmak istedin.Bu databaselerden 1 nolu database düşerse ne olacak? Bu durumda da sql query için sqlproxy gerekecek. Sen sql sorgularını bu proxye soruyorsun o senin için hangi database uygunsa ona soruyor.
Zaten mikroservis diye yapıların çıkmaya başladığı yer de burası oluyor. Mesela 1 nolu databasedeki verilere erişim sağlayıp cevap veren bi servis var, ihtiyacı olan bu servisle konuşuyor. Onun aracılığıyla işler yürütülmeye başlanıyor.
Bununla birlikte session’ın nereye koyulacağı da bir sorun. Session yıllarca diskte tutuldu fakat diskte tutmanın performans yükü gibi birçok problemi çıkmaya başlıyor.Bu duruma çözüm olarak database’e yazıldığında ise yine io işlemine sebep oluyor. Yani query’lerin artmaya başlıyor. Session dediğimiz şey ise geçici bir iş, beyhude. Madem gelip geçici, session’a yazıyoruz ve logout olunca da siliyoruz, o zaman bu sessionlar Redis gibi Memcached gibi session servislerine yazılmaya başlanıyor.
Yani request, web sunucusuna geldi ve Sql proxy’den geçerek uygun database’e gitti. Database’e kullanıcının kullanıcı adı ve parolayı sorarak valide ettin. Web sunucusu olarak session oluşturup session servisine yazdın. Bundan sonra hep redise gitmeye başlıyorsun. Bu session yapılarında session; key-value olarak memoryde tutulduğu için de oldukça hızlı oluyor. Tabi ki eğer redis veya başka bir session yapısı düşerse tekrar ayağa kalkana kadar kimse login olamaz. Bu sebeple redisi de backuplamak gerekiyor.
Bir diğer konu static dosyalar(Fotoğraflar vb.),bu dosyalar nerede olacak?
Örnek olarak 1 nolu web sunucuna gittim ve dosyayı yükledim. Tamam da yarin 2 nolu suncuya gidersem ne olacak? Yüklediğimiz fotoğraf gitmiş olacak bu sefer. Bu tür durumlar nedeniyle statik dosyaları tutup yönetebileceğin CDN gündeme geliyor. Artık bu sebeple Shell Upload zafiyeti modern sitelerde yok. Çünkü o dosya uygulama sunucunun diskine dokunmadan CDN sunumu yapan sunuculara gidiyor. Yüklediğin görselin dosya adı database’e kaydediliyor ve web uygulaması HTML içerik üretip link vereceği zaman database’den bu değeri alıp, o linki kullanıcıya verdiğinde, o resmi çağırmak isteyen browser direkt CDN’e gidiyor. Yani kullanıcı anlattığımız dünyaya hiç dokunmuyor bile.
Bununla birlikte örnek olarak Amerika’dan, Türkiye’den veya Çin’den gelen kullanıcı, benim sunucuma bu bir tane resmi almak için gelmesine gerek yok. Gerek olmadığı içindir ki Cloudflare’in konusu güvenlik değil. Tüm trafik Cloudflare üzerinden geçiyor ve Cloudflare bir kere bu resmi okuduktan sonra dünyadaki tüm node’lara aynı cache’i yayınlıyor. Böylece bir sonraki gelişte biz tekrar bu görseli kullanıcıya vermek yerine en yakın Cloudflare node’u bu adama otomatik cevap dönüyor. Aynı zamanda sadece görseller değil Javascript’ler de bu şekilde yayınlanmakta.