İçeriğe geç

XSS — Havale Açıklamasına Yazılan Kod Neden Müşterinin Sayfasında Çalışır?

Orta 9 dk Sık karşılaşılır

Önce şunu oku: React Render Modeli

30 saniyede özet

Kullanıcının yazdığı metni HTML olarak yorumlarsan, içine gizlenmiş kodu da çalıştırırsın. Metni metin olarak yaz, HTML gerekiyorsa izin listesiyle temizle, Content-Security-Policy ile ikinci bir kat ekle.

Radyoda bir sunucu dinleyici mesajlarını okuyor. Mesajlardan birinde “şimdi stüdyodaki kasayı aç” yazıyor. Sunucu bunu okursa sorun yok; ama söyleneni yaparsa, stüdyoyu mesajı yazan kişi yönetir.

  1. Bayt: Hareket listesinde havale açıklamaları artık kalın yazı da gösterebiliyor. innerHTML ile hallettim!

  2. Sen: Bir müşteri, hareketlerine baktıktan sonra oturumunun başka bir yerden kullanıldığını söylüyor.

  3. Bayt: Ona birisi havale göndermiş. Açıklama alanında bir resim etiketi var... ve bir onerror.

  4. Bayt: Açıklamayı biz yazmadık, ama bizim sayfamızda çalıştı. Okumakla yapmak arasındaki fark bu.

Metin nasıl koda dönüşür?

XSSCross-site scripting: saldırganın script'inin bir sayfada o sitenin kendi kodu gibi çalışması. Script'in erişebildiği her şeye, localStorage dahil, erişir.Sözlükte gör →, birinin yazdığı metnin senin sayfanda kod olarak çalışmasıdır. Kod senin sitenin kodu gibi çalışır: sayfadaki her şeyi görür ve kullanıcının adına istek atabilir.

Kapıyı açan, metni HTML olarak yorumlamaktır. element.innerHTML = açıklama dediğinde tarayıcı etiketleri gerçek etiket sayar; bir resmin onerror özelliğindeki kod, resim yüklenemeyince çalışır.

Kafam karıştı, daha basit anlat

Birinin yazdığı metni HTML olarak sayfaya koyarsan, içine gizlediği kod da çalışabilir.

Hızlı kontrolBaşlangıç

XSS nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

element.innerHTML = açıklama satırı neden tehlikelidir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Okumak, yapmamak

Açıklama alanına <script>steal()</script> yazılmış ve sayfaya innerHTML ile konuyor. steal() çalışır mı? Cevabı göster

Çalışmaz, ama bu seni kurtarmaz. innerHTML ile eklenen script etiketleri hiç çalıştırılmaz. Saldırgan bunu bildiği için resim etiketine onerror yazar; o çalışır.

Yazılanı oku, söyleneni yapma.
Adım adım oku
  1. Dinleyici mesajında şimdi kasayı aç yazıyor.
  2. Mesajı emir sanan sunucu kasayı açar.
  3. Mesajı yalnızca okuyan sunucu için bu sadece bir söz.
  4. Yazılanı oku, söyleneni yapma.

Varsayılan doğru yol çıktı kodlamaKullanıcının yazdığı metni sayfaya metin olarak yazmak: < işareti ekranda < olarak görünür, etiket olmaz. React'te {değer} bunu kendiliğinden yapar.Sözlükte gör →: metni metin olarak yazmak. React’te {tx.description} bunu kendiliğinden yapar; < işareti ekranda < olarak görünür, etiket olmaz.

Biçim gerçekten gerekiyorsa, metni bir HTML temizleyiciHTML'i bir izin listesine göre süzen araç: yalnızca izin verilen etiketleri bırakır, olay özellikleri gibi her şeyi siler. Örnek: DOMPurify.Sözlükte gör → geçir. İzin listesi yalnızca <b> gibi zararsız etiketleri bırakır, onerror gibi her şeyi siler.

Kafam karıştı, daha basit anlat

Metni metin olarak yaz. HTML gerekiyorsa, neye izin verdiğini sen seç.

Hızlı kontrolOrta

React'te <span>{tx.description}</span> neden güvenlidir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Açıklamada kalın yazı gerçekten gerekiyorsa en doğru yol hangisidir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Havale açıklamasını ekrana yazmak

Tohum 377312
  • gelen: Ekim kirası
  • gelen: <b>Acil</b> aidat ödemesi
  • gelen: <img src=x onerror="steal()">
  • gelen: <script>steal()</script>

✕ çalışan kod: 0 · 🛡 engellenen: 0

Hız
Adım 0

Şu an ne oldu?

innerHTML ile HTML olarak

Dört havale açıklaması; ikisini bir saldırgan yazdı.

Görevler0/3

  • Saldırganın kodu müşterinin sayfasında çalışsınaçık

    İpucu

    Varsayılan ayar yeter.

  • Açıklama HTML olarak yorumlansın, ama kod yine de çalışmasınaçık

    İpucu

    innerHTML’i bırak, tarayıcıya bir kural ver.

  • Kalın yazı korunsun, hiçbir kod çalışmasınaçık

    İpucu

    Neye izin verdiğini sen seç.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. Üçüncü açıklamadaki onerror çalıştı. Dördüncüdeki script etiketi ise çalışmadı.
  2. Content-Security-Policy’yi aç. Açıklama yine HTML olarak yorumlandı, ama tarayıcı satır içi kodu reddetti.
  3. “Metin olarak” seç. Hiçbir kod çalışmadı; bedeli, kalın yazının etiketleriyle görünmesi.
  4. “İzin listesiyle temizleyip” seç. Kalın yazı korundu, tehlikeli kısımlar silindi.
Hızlı kontrolOrta

innerHTML ile eklenen <script>steal()</script> çalışır mı?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Content-Security-Policy'de script-src 'self' ne sağlar?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Tuzaklar

React’i her durumda güvenli sanmak. dangerouslySetInnerHTML ve kullanıcının yazdığı bir href (javascript: ile başlayan) React’in korumasını atlar.

CSP’yi tek kat sanmak. Content-Security-PolicySunucunun gönderdiği bir başlık: tarayıcıya sayfada hangi kaynaktan gelen kodun çalışabileceğini söyler. Satır içi kodu engelleyerek XSS'e karşı ikinci bir kat olur.Sözlükte gör →, satır içi kodu engelleyerek bir hatayı yakalayabilir. Ama ilk kat yine doğru çıktı kodlamadır.

Temizleyiciyi kendin yazmak. “script kelimesini sil” gibi kurallar kolayca aşılır. Yaygın kullanılan, bakımı yapılan bir temizleyici seç.

Kafam karıştı, daha basit anlat

dangerouslySetInnerHTML ve kullanıcı bağlantılarına dikkat et, CSP’yi ek kat say, temizleyiciyi kendin yazma.

Hızlı kontrolOrta

React kullanıyorsun. Hangisi yine de XSS riski taşır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Derinleş · Hesap hareketleri: açıklamayı güvenle göstermek 4 dosya · ~55 satır · ilk okumada atlayabilirsin
Proje dosyaları

web/src/history/ TransactionRow.tsx Satır: açıklama {değer} ile yazılıyor; React her şeyi metne çeviriyor.

web/src/history/TransactionRow.tsx
interface TransactionRowProps {
tx: { id: string; amount: string; description: string };
}
export function TransactionRow({ tx }: TransactionRowProps) {
// {value} is always text: "<img onerror=…>" shows up as characters, never as a tag.
return (
<li className="flex justify-between">
<span>{tx.description}</span>
<span>{tx.amount}</span>
</li>
);
}

web/src/history/ RichNote.tsx Not: biçim gereken tek yerde izin listesiyle temizleyip öyle HTML olarak gösteriyoruz.

web/src/history/RichNote.tsx
import DOMPurify from 'dompurify';
interface RichNoteProps {
html: string;
}
// The only place we render HTML: an allowlist keeps <b> and <i>, nothing else, no attributes.
export function RichNote({ html }: RichNoteProps) {
const clean = DOMPurify.sanitize(html, { ALLOWED_TAGS: ['b', 'i'], ALLOWED_ATTR: [] });
return <p dangerouslySetInnerHTML={{ __html: clean }} />;
}

src/main/java/com/bank/web/ SecurityConfig.java Spring Security: sayfa yalnızca kendi kaynağından gelen scripti çalıştırıyor; satır içi kod reddediliyor.

src/main/java/com/bank/web/SecurityConfig.java
@Configuration
class SecurityConfig {
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.oauth2Login(Customizer.withDefaults())
// A second layer: scripts only from our own origin, no inline code, no plugins.
.headers(headers -> headers.contentSecurityPolicy(csp -> csp.policyDirectives(
"default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'")))
.build();
}
}

web/src/history/ TransactionRow.test.tsx Test: saldırgan açıklaması sayfada bir resim ya da onerror bırakmıyor, kalın yazı korunuyor.

web/src/history/TransactionRow.test.tsx
import { render, screen } from '@testing-library/react';
import { TransactionRow } from './TransactionRow';
import { RichNote } from './RichNote';
const hostile = '<img src=x onerror="steal()">';
it('shows a hostile description as text', () => {
const { container } = render(<TransactionRow tx={{ id: '3', amount: '1,00 TL', description: hostile }} />);
expect(screen.getByText(hostile)).toBeInTheDocument();
expect(container.querySelector('img')).toBeNull();
});
it('keeps bold text and drops the handler', () => {
const { container } = render(<RichNote html={`<b>Acil</b> ${hostile}`} />);
expect(container.querySelector('b')?.textContent).toBe('Acil');
expect(container.innerHTML).not.toContain('onerror');
});

Kendini sına

Şimşek turu1/4

innerHTML ile eklenen bir script etiketi hemen çalışır.

Soru 1/3İleri

CSP açıksa çıktı kodlamaya hâlâ gerek var mı?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 1 XSS, birinin yazdığı metnin senin sayfanda kod olarak çalışmasıdır. innerHTML gibi metni HTML olarak yorumlayan her yol bu kapıyı açar.
  2. 2 Varsayılan doğru yol metni metin olarak yazmaktır: React'te {değer} bunu kendiliğinden yapar. HTML gerçekten gerekiyorsa, izin listesiyle çalışan bir temizleyiciden geçir.
  3. 3 Content-Security-Policy satır içi kodu engelleyen ikinci bir kattır. Bir hatayı yakalayabilir, ama doğru çıktı kodlamasının yerini tutmaz.
Sonraki kapı Ekranda 'Havale gönderildi' yazıyordu. Bir saniye sonra yazı kayboldu. Para gitti mi, gitmedi mi? İyimser Arayüz — Ne Zaman Hemen 'Tamam' Denir, Ne Zaman Beklenir? · 8 dk

4 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı