İçeriğe geç

SSRF — Müşterinin Verdiği Adresi Sunucu Neden Çağırmamalı?

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

Önce şunu oku: Spring Security Filter Chain

30 saniyede özet

Kullanıcının verdiği bir URL'yi sunucu çağırırsa, istek sunucunun yetkileriyle gider ve iç ağa ulaşabilir. Yazıya bakan yasak listesi kolayca atlatılır; izin listesi, çözülen IP kontrolü ve yönlendirmesiz istek bunu durdurur.

Bir ofiste getir götür işlerine bakan bir görevli var. Kapıdaki ziyaretçi ondan bir adresten kâğıt getirmesini istiyor. Görevlinin personel kartı arşivi ve kasa odasını da açıyor; ziyaretçinin hiç giremeyeceği yerleri.

  1. Bayt: Kurumsal müşteriler bir adres veriyor, biz de faturalarını oradan indiriyoruz. Ne güzel.

  2. Sen: Biri adres olarak 169.254.169.254 yazmış. İnen dosyada bulut hesabımızın geçici anahtarları var!

  3. Bayt: Hemen 169.254'ü yasakladık. Ertesi gün aynı adres bir sayı olarak yazılmış geldi.

  4. Bayt: Neyin yasak olduğunu değil, nereye gidebileceğimizi yazmamız gerekiyor.

İstek kimin adına gidiyor?

Kullanıcının verdiği bir adresi sunucu çağırdığında, istek sunucunun ağ konumundan ve yetkileriyle gider. Saldırganın sunucuya kendi seçtiği bir adresi çağırtmasına SSRFSaldırganın sunucuya kendi seçtiği bir adresi çağırtması. Sunucu, saldırganın ulaşamadığı iç servislere ulaşabildiği için tehlikelidir.Sözlükte gör → denir.

En çok hedeflenen yerlerden biri bulut metadata servisiBulut makinesinin içinden 169.254.169.254 adresinde çalışan, makine hakkında bilgi ve bazen geçici kimlik bilgisi veren servis.Sözlükte gör →. Makinenin içinden 169.254.169.254 adresinde çalışır ve geçici kimlik bilgileri verebilir.

Kafam karıştı, daha basit anlat

Sunucu, müşterinin ulaşamadığı yerlere ulaşır. Müşterinin verdiği adresi çağırmak, ona sunucunun kartını vermektir.

Hızlı kontrolBaşlangıç

SSRF nedir?

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

Sunucunun çağırdığı bir adres neden tehlikeli olabilir?

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

Yasak listesi neden yetmez?

Sunucu, adresin yazısında localhost ya da 169.254 geçiyorsa reddediyor. Saldırgan adres olarak http://2852039166/ yazdı. Ne olur? Cevabı göster

İstek metadata servisine gider. 2852039166, 169.254.169.254’ün tek bir sayı olarak yazılmış hâlidir. Yasak listesi yazıya baktı; yazıda yasak hiçbir şey yoktu.

Yalnızca izinli adreslere git.
Adım adım oku
  1. Ziyaretçi: şu adresten bir kâğıt getir.
  2. Görevlinin kartı kasa odasını da açıyor.
  3. Kasa odası yasak, ama oda numarası değil.
  4. Yalnızca izinli adreslere git.

Yasak listesi yazıya bakar. Aynı adresin başka bir yazımını ya da masum görünen bir adresin içeriye yönlendirmesini görmez.

Sağlam yol tersidir: yalnızca bilinen alan adlarına izin ver, adı çözdükten sonra IP’nin iç ağda olmadığını kontrol et ve yönlendirmeleri takip etme.

Kafam karıştı, daha basit anlat

Yasakları sayma; izin verdiğin adresleri yaz ve çözülen IP’ye bak.

Hızlı kontrolOrta

Bulut metadata servisi (169.254.169.254) neden hedef olur?

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

Yasak listesi "169.254" yazısını engelliyor. Saldırgan nasıl aşabilir?

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

Kendin gör

Fatura indiren sunucu

Tohum 427631
  1. https://fatura.firma.com.tr/ocak.pdf
    gerçek fatura
  2. http://localhost:8080/actuator/env
    kendi uygulamamızın ayarları
  3. http://169.254.169.254/latest/meta-data/
    bulut metadata servisi
  4. http://2852039166/latest/meta-data/
    aynı adres, sayı olarak yazılmış
  5. https://cdn.fatura-ornek.net/a.pdf
    iç ağdaki yönetim paneline yönlendiriyor

✕ iç ağa ulaşan istek: 0

Hız
Adım 0

Şu an ne oldu?

Yasak listesi: "localhost" ve "169.254" geçmesin

Müşterinin verdiği adresleri sunucumuz çağırıyor; sunucu, müşterinin göremediği iç ağı görebilir.

Görevler0/3

  • Bulut metadata servisine ulaşılsınaçık

    İpucu

    Kontrol yok.

  • Yasak listesine rağmen iç ağa ulaşılsınaçık

    İpucu

    Yasak listesi.

  • Yalnızca gerçek fatura indirilsinaçık

    İpucu

    İzin listesi.

Olay günlüğü (0)

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

  1. Varsayılanla oynat. Yasak listesi localhost’u ve 169.254’ü durdurdu; ama sayı olarak yazılan adres ve yönlendirme iç ağa ulaştı.
  2. “Kontrol yok” seç. Dört iç adresin dördü de indirildi, metadata dahil.
  3. “İzin listesi” seç. Yalnızca gerçek fatura indirildi.
Hızlı kontrolOrta

SSRF'e karşı en sağlam yaklaşım hangisi?

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

Masum görünen bir adres iç ağdaki bir panele yönlendiriyor. HTTP istemcisi yönlendirmeyi takip ederse ne olur?

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

Tuzaklar

Adı kontrol edip ayrıca bağlanmak. Kontrol ile bağlantı arasında aynı ad başka bir IP’ye çözülebilir. Adı bir kez çöz, IP’yi kontrol et ve bağlantıyı o IP’ye yap.

Yalnızca koda güvenmek. Uygulamanın dışarı çıkışını ağ kurallarıyla yalnızca gerekli adreslere sınırla. Bulutta metadata servisinin token isteyen sürümünü kullan.

Özelliği gereğinden geniş tutmak. Önce sor: müşteri dosyayı kendisi yükleyemez mi? En güvenli istek, hiç atılmayandır.

Kafam karıştı, daha basit anlat

Kontrol ettiğin IP’ye bağlan, ağda da sınır koy, özelliği dar tut.

Hızlı kontrolİleri

Adı kontrol edip sonra ayrıca bağlanmak neden yetmeyebilir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Derinleş · Kurumsal bankacılık: fatura indirme, yalnızca izinli adreslere 3 dosya · ~76 satır · ilk okumada atlayabilirsin
Proje dosyaları

corporate/src/main/java/com/bank/corporate/invoice/ InvoiceUrlPolicy.java İzin listesi: müşterinin önceden kayıtlı fatura alan adları; yalnızca HTTPS.

corporate/src/main/java/com/bank/corporate/invoice/InvoiceUrlPolicy.java
@Component
class InvoiceUrlPolicy {
private final RegisteredInvoiceHosts hosts;
InvoiceUrlPolicy(RegisteredInvoiceHosts hosts) {
this.hosts = hosts;
}
/** Returns the one address we will connect to, or throws. */
InetAddress approve(UUID customerId, URI uri) {
if (!"https".equals(uri.getScheme())) {
throw new RejectedUrlException("Yalnızca https adresleri kabul edilir.");
}
if (!hosts.isRegistered(customerId, uri.getHost())) {
throw new RejectedUrlException("Bu alan adı fatura adresi olarak kayıtlı değil.");
}
try {
InetAddress address = InetAddress.getByName(uri.getHost()); // resolve once
if (address.isLoopbackAddress() || address.isLinkLocalAddress()
|| address.isSiteLocalAddress() || address.isAnyLocalAddress()) {
throw new RejectedUrlException("Adres iç ağa çıkıyor.");
}
return address;
} catch (UnknownHostException e) {
throw new RejectedUrlException("Alan adı çözülemedi.");
}
}
}

corporate/src/main/java/com/bank/corporate/invoice/ InvoiceDownloader.java Adres kontrolü: ad bir kez çözülür; iç ağ, loopback ve link-local IP'ler reddedilir.

corporate/src/main/java/com/bank/corporate/invoice/InvoiceDownloader.java
@Service
class InvoiceDownloader {
private static final long MAX_BYTES = 10 * 1024 * 1024;
private final InvoiceUrlPolicy policy;
private final HttpClient http = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NEVER) // a redirect could lead inside
.connectTimeout(Duration.ofSeconds(3))
.build();
InvoiceDownloader(InvoiceUrlPolicy policy) {
this.policy = policy;
}
byte[] download(UUID customerId, URI uri) throws IOException, InterruptedException {
InetAddress approved = policy.approve(customerId, uri);
// Production code pins the connection to `approved` (custom DNS resolver or
// socket factory) so a second lookup cannot return a different address.
HttpResponse<InputStream> response = http.send(
HttpRequest.newBuilder(uri).timeout(Duration.ofSeconds(10)).GET().build(),
HttpResponse.BodyHandlers.ofInputStream());
if (response.statusCode() != 200) {
throw new RejectedUrlException("Fatura indirilemedi: " + response.statusCode());
}
try (InputStream body = response.body()) {
return body.readNBytes((int) MAX_BYTES);
}
}
}

corporate/deploy/ network-policy.yaml İstemci: yönlendirme takip edilmez, süre ve boyut sınırlı.

corporate/deploy/network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: corporate-egress
spec:
podSelector:
matchLabels:
app: corporate
policyTypes: [Egress]
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16]
ports:
- port: 443
protocol: TCP

Kendini sına

Şimşek turu1/4

Sunucunun çağırdığı adres, sunucunun yetkileriyle çağrılır.

Soru 1/3Orta

SSRF'in etkisini azaltan altyapı önlemi hangisi?

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

Aklında kalacak üç şey

  1. 1 Sunucunun çağırdığı adres, müşterinin değil sunucunun ağ konumu ve yetkileriyle çağrılır. Müşterinin göremediği iç servisler sunucuya açıktır.
  2. 2 Yazıya bakan yasak listesi, aynı adresin başka yazımına ya da bir yönlendirmeye yenilir.
  3. 3 Yalnızca izinli adreslere git, çözülen IP'nin iç ağda olmadığını kontrol et, yönlendirmeleri takip etme.
Sonraki kapı Rapor uygulaması yıllardır Tomcat'te çalışıyordu. Aynı WAR'ı WildFly'a koydun; açılmadı. Sunucu neye itiraz etti? WAR ve Uygulama Sunucusu — Tomcat'te Çalışan, WildFly'da Neden Açılmadı? · 9 dk

4 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı