Clickjacking saldırısı kötücül bir sayfanın kullanıcı adına hedef sitede tıklamalar yapmasına olanak saÄlar.
Sonradan düzeltilmiÅ olsa da Twitter, Facebook ve PayPalâın da bulunduÄu birçok site, zamanında bu saldırı ile ele geçirilmiÅtir.
Mantık
Saldırının arkasındaki mantık oldukça basittir.
ÃrneÄin Facebook ile yapılan bir clickjacking saldırısı böyle iÅler:
- Ziyaretçi herhangi bir neden veya yolla kötücül siteyi ziyaret eder.
- Kötücül sitede zararsız ve ilgi çekici bir baplantı bulunur (örneÄin âZengin olmak için tıklaâ veya âbu kedinin neler yaptıÄına inanamayacaksınızâ).
- Kötücül sayfa baÄlantının üzerine facebook.comâdan
srcâsi olan Åeffaf bir<iframe>yerleÅtirir. Bu<iframe>Åeffaf bir âBeÄenâ butonunun tam baÄlantının üzerine gelmesini saÄlar. Genellikle yerleÅtirme içinz-indexkullanılır. - Ziyaretçi baÄlantıya tıklamayı denerken aslında Åeffaf olan butona tıklar.
Ãrnek
Bu kod bir kötücül sayfa örneÄidir. Daha iyi görülebilmesi amacıyla <iframe> yarı Åeffaf olarak ayarlanmıÅtır (Gerçek bir kötücül sayfada bu <iframe> tamamen Åeffaftır):
<style>
iframe { /* Hedef siteden alınan iframe */
width: 400px;
height: 100px;
position: absolute;
top:0; left:-20px;
opacity: 0.5; /* Gerçekte opacity:0 */
z-index: 1;
}
</style>
<div>Zengin olmak için tıkla:</div>
<!-- Hedef sitenin url'si -->
<iframe src="/clickjacking/facebook.html"></iframe>
<button>Buraya tıkla!</button>
<div>Ve artık zenginsin (ve ayrıca beni Facebook'ta beÄenmeni saÄladım)!</div>
Saldırının tam bir örneÄi:
<!DOCTYPE HTML>
<html>
<body style="margin:10px;padding:10px">
<input type="button" onclick="alert('facebook.html'de beÄen butonuna basıldı!')" value="BEGENDIM">
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 5px;
left: -14px;
opacity: 0.5;
z-index: 1;
}
</style>
<div>Zengin olmak için tıkla:</div>
<!-- The url from the victim site -->
<iframe src="facebook.html"></iframe>
<button>Buraya tıkla!</button>
<div>...Ve zengin oldun (ve sayfamı beÄendin)!</div>
</body>
</html>Bu örnekte elimizde yarı Åeffaf bir <iframe src="facebook.html"> var, ve burada butonun üstünde kaldıÄını görebiliyoruz. Bu butona basılacak bir tıklama aslında iframe tarafından yakalanır, ancak bu olay iframe Åeffaf olduÄu için kullanıcı tarafından görülmez.
Sonuç olarak eÄer kullanıcının Facebook hesabı zaten açıksa sayfayı beÄenmiÅ olur. EÄer örnekte Twitter hedef site olsaydı, kullanıcı sayfayı Twitterâda takip etmiÅ olurdu.
Aynı örneÄin <iframe> için opacity:0 ayarlanmıÅ, daha gerçekçi bir versiyonu:
<!DOCTYPE HTML>
<html>
<body style="margin:10px;padding:10px">
<input type="button" onclick="alert('facebook.html'de beÄen butonuna basıldı!')" value="BEGENDIM!">
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 5px;
left: -14px;
opacity: 0;
z-index: 1;
}
</style>
<div>Zengin olmak için tıkla:</div>
<!-- Hedef sitenin url'si -->
<iframe src="facebook.html"></iframe>
<button>Buraya tıkla!</button>
<div>...Ve zengin oldun (ve sayfamı beÄendin)!</div>
</body>
</html>Saldırının gerçekleÅmesi için tek gereken kötücül sayfadaki <iframe>'in tam olarak baÄlantının üstüne yerleÅmesidir. Bu olay çoÄunlukla CSS ile mümkündür.
Bu saldırı sadece fare hareketlerini kapsar.
Teknik olarak, saldıracaÄımız nesne bir metin alanı olsaydı, bir iframeâi tam olarak alanın üzerine getirerek saldırıyı deneyebilirdik. Böylece gerçek metin alanına yazdıÄını düÅünen kullanıcı aslında iframeâin metin alanına yazardı.
Ancak, bu durumds kullanıcının yazdıkları ekranda görünmez.
Genellikle kullanıcı ekranda yazdıÄını göremediÄinde yazmayı keser, bu da bu saldırıyı metin alanalrı için kullanıÅsız kılar.
Eski yöntem savunmalar (zayıf)
Bu saldırıya karÅı en eski savunma yöntemi sayfanın iframe olarak açılmasını engelleyen bir JavaScript betiÄidir. Bu yöntem ayrıca âframebustingâ olarak da bilinir.
Betik Åöyle görünür:
if (top != window) {
top.location = window.location;
}
Mantık: EÄer asıl sayfa en üstte olmadıÄını fark ederse, kendini en üste taÅır.
Bu yöntem, etrafından dolaÅma yolları nedeniyle güvenilmezdir. Bu yöntemlerden bazılarını inceleyelim.
Ãste taÅımayı engellemek
beforeunload olayından önce top.locationâın deÄiÅmesinden kaynaklanan üste çıkma eylemi engellenebilir.
Ãstteki (saldırgana ait) sayfa bu olaya bir iÅleyici baÄlayarak iframe top.locationâı deÄiÅtirmeyi denediÄinde kullanıcıya ayrılamk isteyip istemediÄini soran bir mesaj gösterebilir.
ÃrneÄin:
window.onbeforeunload = function() {
window.onbeforeunload = null;
return "Gerçekten tüm kedileri görmeden bu sayfadan ayrılmak istiyor musunuz?";
};
ÃoÄu senaryoda, kullanıcı iframeâin varlıÄını bilmediÄinden dolayı âHayırâ cevabını verecektir. Sonuçta gördükleri tek Åey üzerinde kedi videoları olan en üstteki sayfa, niye ayrılmak istesinler ki? Yani, top.location deÄiÅmeyecek.
İŠüzerinde:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div>top.location'ı javascript.info'ya çevirir</div>
<script>
top.location = 'https://javascript.info';
</script>
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
<style>
iframe {
width: 400px;
height: 100px;
position: absolute;
top: 0;
left: -20px;
opacity: 0;
z-index: 1;
}
</style>
<script>
function attack() {
window.onbeforeunload = function() {
window.onbeforeunload = null;
return "Gerçekten tüm kedileri görmeden ayrılmak istiyor musunuz?";
};
document.body.insertAdjacentHTML('beforeend', '<iframe src="iframe.html">');
}
</script>
</head>
<body>
<p>Bir tıklamadan sonra kullanıcı ayrılmak isteyip istemediÄine dair garip bir mesaj alır.</p>
<p>Büyük ihtimalle "Hayır" cevabını vereceklerdir, ve iframe koruması çöker.</p>
<button onclick="attack()">"Korumalı" bir iframe ekle</button>
</body>
</html>Sandbox niteliÄi
sandbox niteliÄi tarafından kısıtlanan özelliklerden biri sayfa hareketidir. Sandbox niteliÄine sahip bir iframe top.location deÄerini deÄiÅtiremez.
Yani iframeâi sandbox="allow-scripts allow-forms" niteliÄiyle ekleyebiliriz. Nitelikteki "allow-scripts allow-forms" kısmı sandbox niteliÄindeki kısıtlamaları kaldırarak betik ve formların çalıÅmasını saÄlar ancak allow-top-navigation olmadıÄından iframe üste çıkamaz.
Kod örneÄi:
<iframe sandbox="allow-scripts allow-forms" src="facebook.html"></iframe>
Bu basit korumanın arkasından dolaÅacak tabii ki daha fazla yöntem var.
X-Frame-Options
Sunucu-taraflı X-Frame-Options baÅlıÄı bir sayfanın iframe içinde gösterilmesine izin verebilir veya reddedebilir.
BaÅlıÄın sunucu tarafından gönderilmesi Åarttır, tarayıcı bu baÅlıÄı <meta> etiketinde görürse yok sayar. Yani <meta http-equiv="X-Frame-Options"...> etkisizdir.
BaÅlık üç deÄerden birini taÅıyabilir:
DENY- Sayfayı asla iframe içinde gösterme.
SAMEORIGIN- Sayfanın iframe içinde gösterilmesine ancak ana dosya aynı kaynaktansa izin ver.A
ALLOW-FROM domain- Sayfanın iframe içinde gösterilmesine ancak ana dosya belirtilen alan adından geliyorsa izin ver.
ÃrneÄin, Twitterâda X-Frame-Options: SAMEORIGIN kullanılıyor.
Sonuç:
<iframe src="https://twitter.com"></iframe>
Tarayıcınıza göre yukarıdaki iframe ya boÅtur ya da tarayıcının bu sayfa hareketine izin vermediÄi konusunda sizi uyaracaktır.
İÅlevsiz olarak göstermek
X-Frame-Options baÅlıÄının bir de kötü yanı var: DiÄer siteler, iyi bir nedenleri olsa bile, bu baÅlıÄı taÅıyan siteyi bir iframe içinde gösteremeyecek.
Yine de, baÅka çözümler var⦠ÃrneÄin, bir <div> oluÅturup height: 100%; width: 100%; deÄerlerini kullanarak sayfayı âkaplayabilirizâ, böylece bu <div> gelen tüm tıklamaları engeller, eÄer bu korumaya ihtiyaç duymazsak veya window == top olursa da yok olur.
Bunun gibi:
<style>
#protector {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 99999999;
}
</style>
<div id="protector">
<a href="/" target="_blank">Siteye git</a>
</div>
<script>
// EÄer üstteki sayfa baÅka bir kaynaktansa burada bir hata oluÅacak
// ancak sorun deÄil
if (top.document.domain == document.domain) {
protector.remove();
}
</script>
Ãrnek:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<style>
#protector {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 99999999;
}
</style>
</head>
<body>
<div id="protector">
<a href="/" target="_blank">Siteye git</a>
</div>
<script>
if (top.document.domain == document.domain) {
protector.remove();
}
</script>
Bu yazı her zaman görünüt halde.
Ancak eÄer sayfa baÅka bir alan adındaki bir dosyadan gelseydi üzerindeki div herhangi bir aksiyonu engellerdi.
<button onclick="alert(1)">Tıklama burada çalıÅmazdı</button>
</body>
</html><!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<iframe src="iframe.html"></iframe>
</body>
</html>Samesite çerez niteliÄi
samesite çerez niteliÄi clickjacking saldırılarını engelleyebilen niteliklerden biridir. Bu niteliÄin amacı kullanıcı site dıÅındaki baÅka bir siteye gitmek istemediÄinde o siteye çerezleri göndermemektir. Ãapraz site sahteciliÄi saldırılarına karÅı tasarlanmıŠolmasına raÄmen clickjackingâe karÅı doÄal bir koruma saÄlar, çünkü genellikle bir clickjacking saldırısı baÅka bir siteye bir istek gönderilmesine neden olur. Bir çerez samesite niteliÄine sahip iken, deÄerinin strict veya lax olmasına bakılmaksızın iframe içinde açılan bir sayfayla paylaÅılmaz.
samesite niteliÄi HTTP cevap baÅlıklarıyla veya JavaScript ile tanımlanabilir. HTTP kullanırken böyle gözükür:
Set-Cookie: demoCookie=demoValue; samesite=lax
veya
Set-Cookie: demoCookie=demoValue; samesite=strict
JavaScript için:
document.cookie = "demoCookie=demoValue; SameSite=Lax";
document.cookie = "demoCookie=demoValue; SameSite=Strict";
DeÄer lax iken bu türden istekler engellenir:
- Form POST gönderimi (<form method=âPOSTâ action=ââ¦â>)
- iframe (<iframe src=ââ¦â></iframe>)
- AJAX ($.get(ââ¦â))
- Görüntü (<img src=ââ¦â>)
- Betik (<script src=ââ¦â></script>)
- Stylesheet (<link rel=âstylesheetâ type=âtext/cssâ href=ââ¦â>)
DeÄer strict iken lax deÄerine ek olarak bunlar engellenir:
- Link tıklamaları (<a href=ââ¦â></a>)
- Ãnbetimleme (<link rel=âprerenderâ href=ââ¦â/>)
- Form GET gönderimi (<form method=âGETâ action=ââ¦â>)
Bu senaryoda iframe istekleri ilgimizi çeken yer. Clickjacking saldırısı durumnda, nitelikten dolayı kullanıcı örneÄin Facebookâta giriÅ yapmamıŠsayılacaÄından herhangi bir Åeyi beÄenemez, bu yüzden saldırı sonuçsuz kalır.
samesite niteliÄi çerezlerin kullanılmadıÄı alanlarda iÅlevsiz kalır. Bu zaaf sitelerin iframe içinde çereze ihtiyaç duymayan halka açık sitelerin görüntülenebilmesine olanak verir. ÃrneÄin sadece birden fazla oy verilmesin diye IP adreslerini kaydeden anonim bir oylama sitesi saldırıya açık kalacaktır.
Ãzet
Clickjacking kullanıcıları kötücül bir siteye ne olduÄunu bile anlamadan tıklamaya âsevk edenâ bir yöntemdir. Ãzellikle önemli butonların bulunduÄu sitelerde (örneÄin PayPal) tehlikelidir.
Saldırgan kötücül sayfaya bir baÄlantı paylaÅabilir veya kullanıcıları bu sayfaya çekebilir.
Bir açıdan saldırı âsıÄâ olarak sınıflandırılabilir: sonuçta saldırgan sadece tek bir tıklamatı ele geçiriyor. Ancak, baÅka bir açıdan, eÄer saldırgan baÅka tıklamaların gerekeceÄini biliyorsa aynı yöntemle kullanıcının oralara tıklamasını saÄlayabilir.
Bu saldırı olukça tehilkelidir, çünkü genellikle bir arayüzü tasarlarken saldırganın kullanıcı yerine tıklamasını heasba katmayız. Yani açıklar beklemediÄimiz yerlerden gelebilir.
-
X-Frame-Options: SAMEORIGINniteiÄinin sayfalarda (veya sitelerde) kullanılması önerilir (eÄer site iframe içinde görüntülenmek amacı taÅımıyorsa) -
Sayfanın iframe içinde görüntülenebilir olmasını istiyorsak kaplayıcı bir
divkullanabiliriz, ama önlemlerin alınması gereklidir.
Yorumlar
<code>kullanınız, birkaç satır eklemek için ise<pre>kullanın. EÄer 10 satırdan fazla kod ekleyecekseniz plnkr kullanabilirsiniz)