Bir sabah uygulamanız önbelleği bulamıyor, oturumlar düşmüş, kullanıcı verileri boş dönüyor. redis-cli ile bağlanıp KEYS * çalıştırdığınızda tek bir anahtar görüyorsunuz: içinde bir Bitcoin cüzdan adresi ve "verilerinizi yedekledik, ödeme yapmazsanız yayınlarız" yazan bir not. Aynı senaryonun MongoDB hâlinde koleksiyonlarınız silinmiş, yerine READ_ME adında tek bir koleksiyon bırakılmıştır.
Bu saldırı hedefli değildir. Kimse sizin şirketinizi seçmemiştir. İnternete açık IP aralıklarını sürekli tarayan botlar 6379 ve 27017 portlarını dener, kimlik doğrulaması istenmeyen bir servis bulduğunda içeri girer, veriyi siler ve notu bırakır. Yeni açılmış ve korumasız bırakılmış bir veritabanının bulunması genellikle saatler içinde gerçekleşir; bazı durumlarda dakikalar yeterlidir.
İşin can sıkıcı tarafı, bu duruma düşen sistem yöneticilerinin çoğunun sunucusunda güvenlik duvarı açık olmasıdır. Redis ve MongoDB'nin varsayılan davranışı, bir yapılandırma satırının nasıl ters teptiği ve Docker'ın -p bayrağının UFW kurallarını nasıl atladığı bir araya geldiğinde, "ben portu kapatmıştım" cümlesi teknik olarak doğru ama pratikte yanlış hâle gelir. Aşağıda önce kendi sunucunuzu test edecek, sonra üç katmanda kapatacağız.
Redis ve MongoDB Neden Kimlik Doğrulaması Olmadan Geliyor?#
İki veritabanı da aynı varsayımla tasarlandı: güvenilir bir iç ağda, uygulama sunucusunun yanında çalışacaklar. Kimlik doğrulaması ek gecikme ve işletim yükü demektir; kapalı bir ağda bunun karşılığı yoktur. Bu makul bir tasarım tercihiydi, ancak bulut sunucuların her birinin doğrudan bir genel IP'ye sahip olmasıyla varsayım çöktü.
Her iki proje de zamanla ön tanımlı güvenlik eklediler:
- Redis, 3.2 sürümünden beri
protected-mode yesile gelir. Bu mod,bindsatırı belirtilmemiş ve parola tanımlanmamışsa yalnızca loopback adreslerinden gelen bağlantıları kabul eder. Ayrıca paket kurulumlarının çoğunda yapılandırma dosyasındabind 127.0.0.1 -::1satırı hazır gelir. - MongoDB, 3.6 sürümünden beri paketlenmiş
mongod.confdosyasındabindIp: 127.0.0.1ile gelir. Ancak kimlik doğrulaması (security.authorization) hâlâ varsayılan olarak kapalıdır.
Kritik nokta şudur ve çoğu rehberde atlanır: Redis'te bind 0.0.0.0 satırını siz açıkça yazdığınız anda korumalı mod devreye girmez. Korumalı mod, "yönetici bind ayarına hiç dokunmamışsa" durumunu korur; siz açıkça bir adres belirttiğinizde bunu bilinçli bir tercih sayar. Yani "uygulama sunucusundan bağlanamıyorum" diye bind satırını 0.0.0.0 yapıp parola koymamak, Redis'i tamamen açık bırakmanın en yaygın yoludur.
MongoDB tarafında da denklem aynıdır: bindIp değerini 0.0.0.0 yapıp authorization: enabled satırını eklememek, veritabanınızı okuma ve yazma izniyle internete bırakır. Redis'in genel çalışma mantığına yeniyseniz Redis nedir yazısı iyi bir başlangıçtır.
Sunucunuzda Port Gerçekten Açık mı? Üç Katmanlı Test#
Tek bir komuta güvenmeyin; üç farklı katmandan bakın.
1. Sunucunun kendi üzerinden: servis hangi adresi dinliyor?
sudo ss -tlnp | grep -E '6379|27017|5432|3306|9200|11211'
Çıktının ilk sütunundaki adres her şeyi söyler:
| Dinlenen adres | Anlamı |
|---|---|
127.0.0.1:6379 | Yalnızca aynı makineden erişilebilir. İstenen durum. |
0.0.0.0:6379 | Tüm ağ arayüzlerinden erişilebilir. Riskli. |
[::]:6379 | Tüm IPv6 arayüzlerinden erişilebilir. IPv4 kadar riskli. |
10.0.0.5:6379 | Yalnızca o özel ağ arayüzünden. Kabul edilebilir. |
0.0.0.0 görmek tek başına "internete açık" demek değildir; güvenlik duvarı hâlâ durduruyor olabilir. Ama bir sonraki adımı atlamamanız için yeterli sebeptir.
2. Dışarıdan: port gerçekten ulaşılabiliyor mu?
Bu testi sunucunun kendisinden değil, başka bir makineden yapın. Kendi bilgisayarınız veya farklı bir sunucu olabilir:
# Portlar açık mı
nmap -Pn -p 6379,27017,9200,5432,3306,11211 SUNUCU_IP
# Hızlı tek port kontrolü
nc -zvw3 SUNUCU_IP 6379
3. Servis düzeyinde: kimlik doğrulaması isteniyor mu?
Port açık olsa bile parola isteniyorsa durum farklıdır. Dışarıdan deneyin:
# Parola isteniyorsa NOAUTH hatası döner, istenmiyorsa PONG döner
redis-cli -h SUNUCU_IP -p 6379 ping
# MongoDB: veritabanı listesi dönüyorsa kimlik doğrulaması kapalıdır
mongosh "mongodb://SUNUCU_IP:27017" --eval "db.adminCommand({listDatabases:1})"
PONG veya bir veritabanı listesi görüyorsanız durum acildir; yazının son bölümüne geçmeden önce servisi hemen dışarıya kapatın. Portların hangisinin dışarıya açık kalması gerektiğini genel olarak değerlendirmek için sunucuda hangi portlar açık olmalı yazısına bakabilirsiniz.
Docker'da -p 6379:6379 Güvenlik Duvarınızı Nasıl Atlıyor?#
Bu, listedeki en sinsi maddedir ve UFW kullanan sunucuların çoğunu etkiler.
docker run -p 6379:6379 redis veya Compose dosyasındaki ports: - "6379:6379" satırı, portu tüm arayüzlere yayınlar. Bunu yaparken Docker, iptables üzerinde kendi kurallarını yazar ve trafiği nat tablosu ile FORWARD zinciri üzerinden konteynere yönlendirir.
UFW kuralları ise INPUT zincirinde çalışır. Konteynere giden paket INPUT zincirine hiç uğramaz, FORWARD üzerinden geçer. Sonuç: ufw status çıktısında Redis portu hiçbir yerde yazmaz, ufw default deny incoming etkindir, ama port internete tamamen açıktır.
Doğrulaması basittir:
sudo ufw status verbose # Redis portu görünmüyor
sudo iptables -t nat -L DOCKER -n --line-numbers | grep 6379 # ama kural burada
Üç çözüm vardır, tercih sırası şudur:
1. Portu hiç yayınlamayın. Uygulama da aynı Compose ağındaysa konteynerler birbirine servis adıyla ulaşır; ana makineye port açmaya gerek yoktur.
services:
api:
build: .
depends_on: [redis]
environment:
REDIS_URL: redis://redis:6379 # servis adıyla iç ağdan erişim
redis:
image: redis:7-alpine
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
# ports satırı YOK
2. Yayınlamanız gerekiyorsa loopback'e bağlayın. Yerel geliştirme veya bir SSH tüneli için gerekiyorsa adresi açıkça yazın:
ports:
- "127.0.0.1:6379:6379"
Baştaki 127.0.0.1: kısmını yazmamak ile yazmak arasındaki fark, "kapalı" ile "herkese açık" arasındaki farktır.
3. Zorunluysa DOCKER-USER zincirine kural yazın. Docker, FORWARD zincirinde ilk olarak DOCKER-USER zincirine atlar ve bu zinciri asla kendisi temizlemez. Kalıcı kısıtlamaların yeri burasıdır:
sudo iptables -I DOCKER-USER -i eth0 -p tcp --dport 6379 -j DROP
sudo iptables -I DOCKER-USER -i eth0 -s 203.0.113.20 -p tcp --dport 6379 -j ACCEPT
Kuralların yeniden başlatmadan sonra kalması için iptables-persistent gibi bir paketle kaydedilmesi gerekir. Konteyner ağı mantığını derinleştirmek isterseniz Docker network yapılandırma yazısı bu konuyu ayrıntılandırıyor.
Saldırgan Açık Bir Redis'te Ne Yapıyor?#
Verinin okunması ve silinmesi zincirin sadece ilk halkasıdır. Redis, tasarımı gereği yöneticisine disk üzerinde dosya yazma yeteneği verir: kalıcılık dosyasının dizinini ve adını çalışma anında değiştirebilir, ardından belleği diske yazdırabilirsiniz. Kimlik doğrulaması olmayan bir Redis'te bu yetenek doğrudan saldırgana geçer.
Pratikte bunun anlamı şudur: saldırgan, Redis sürecinin yazma izni olduğu herhangi bir yola kendi içeriğini bırakabilir. En bilinen hedefler zamanlanmış görev dizinleri ve SSH yetkili anahtar dosyalarıdır. Redis root olarak çalışıyorsa sonuç, veritabanı ihlalinden çıkıp tam sunucu devralınması hâline gelir.
Bu yüzden pratikte gördüğünüz belirtiler farklı farklı olabilir:
| Belirti | Muhtemel sebep |
|---|---|
| Tek anahtarda fidye notu, veri boş | Klasik silme + fidye botu |
| CPU sürekli %100, bilinmeyen süreç | Kripto madenci yüklenmiş |
~/.ssh/authorized_keys içinde tanımadığınız anahtar | Kalıcı erişim bırakılmış |
crontab -l çıktısında yabancı bir indirme satırı | Yeniden başlatmaya dayanıklı zararlı |
| Redis günlüklerinde bilinmeyen bir "master" bağlantısı | Çoğaltma özelliği kötüye kullanılmış |
Bu nedenle açık bir Redis bulduğunuzda sadece parolayı ayarlayıp geçmek yeterli değildir; sunucunun bütününü şüpheli kabul etmeniz gerekir. Son bölümdeki müdahale adımları bunun içindir.
MongoDB Tarafında Fidye Nasıl İşliyor?#
MongoDB'de fidye saldırıları 2017'de toplu bir dalga hâlinde görüldü ve on binlerce veritabanı silindi. O günden beri yöntem değişmedi: bot açık 27017 portunu bulur, kimlik doğrulaması istenmediğini görür, veritabanlarını siler ve içinde ödeme talebi olan tek bir koleksiyon bırakır.
Bu saldırıların önemli bir kısmında veri aslında kopyalanmaz. Terabaytlarca veriyi indirmek zaman ve bant genişliği ister; otomatik bir kampanya için bu ekonomik değildir. "Yedeğini aldık" cümlesi çoğu vakada blöftür. Ödeme yapan çok sayıda kullanıcının hiçbir şey geri alamamış olması da bunu destekler.
Buna karşılık, verinin gerçekten alınmadığını varsayamazsınız da. Doğru yaklaşım, ağ trafiği ve bağlantı kayıtlarına bakıp yüksek hacimli bir dışa aktarım olup olmadığını kontrol etmektir. Sunucu sağlayıcınızın giden trafik grafiği bu konuda en hızlı göstergedir: silme anı civarında birkaç gigabaytlık bir sıçrama varsa veri gerçekten çıkmış olabilir.
2020'de görülen bir başka dalga ise fidye bile istemedi; koleksiyonları silip yerine rastgele dizeler yazdı. Yani açık bir veritabanının tek riski para talebi değildir, verinin karşılıksız yok edilmesidir. Bu nedenle tek gerçek güvence, sunucudan ayrı bir yerde duran ve geri yüklendiği test edilmiş yedeklerdir; ne sıklıkta yedek alınmalı sorusunun cevabı burada doğrudan hasarın büyüklüğünü belirler.
MongoDB kurulumunuzu sıfırdan doğru yapılandırmak isterseniz MongoDB kurulumu yazısındaki adımlar bu bölümdeki güvenlik ayarlarıyla birlikte okunmalıdır.
Redis'i Kapatma: bind, protected-mode ve requirepass#
Yapılandırma dosyası genellikle /etc/redis/redis.conf yolundadır. Aşağıdaki dört satır çekirdek korumayı sağlar:
# Yalnızca yerel arayüzden dinle
bind 127.0.0.1 -::1
# Korumalı modu açık bırak
protected-mode yes
# Uzun ve rastgele bir parola belirle
requirepass sizin-uzun-rastgele-parolaniz
# Zararlı kullanımı zorlaştıran isteğe bağlı bir katman
rename-command CONFIG ""
Parolayı elle uydurmayın, üretin:
openssl rand -base64 36
rename-command CONFIG "" satırı, dosya yazma zincirinin başlangıç noktasını kapatır; ancak yönetim araçlarınız CONFIG komutuna ihtiyaç duyuyorsa boş bırakmak yerine tahmin edilemez bir ada çevirin. Redis 6 ve sonrasında daha temiz yol ACL kullanmaktır: uygulamaya yalnızca ihtiyacı olan komutları ve anahtar önekini verirsiniz.
# Sadece app: önekindeki anahtarlarda çalışan, tehlikeli komutları olmayan kullanıcı
redis-cli ACL SETUSER uygulama on '>parola' '~app:*' '+@read' '+@write' '-@dangerous'
Değişikliklerden sonra servisi yeniden başlatıp doğrulayın:
sudo systemctl restart redis-server
sudo ss -tlnp | grep 6379 # 127.0.0.1 görmelisiniz
redis-cli ping # NOAUTH hatası beklenen cevaptır
Son olarak Redis'in root yerine kendi sistem kullanıcısıyla çalıştığını doğrulayın; paket kurulumları bunu zaten yapar, ancak elle derlenmiş kurulumlarda sıklıkla atlanır.
MongoDB'yi Kapatma: bindIp ve authorization#
/etc/mongod.conf dosyasında iki bölüm önemlidir:
net:
port: 27017
bindIp: 127.0.0.1
security:
authorization: enabled
Sıralama önemlidir. Kimlik doğrulamasını açmadan önce yönetici kullanıcıyı oluşturun; MongoDB, kimlik doğrulaması açıkken hiç kullanıcı yoksa yerel makineden ilk kullanıcının oluşturulmasına izin verir, ancak bu istisnaya güvenmek yerine sırayı doğru kurmak daha rahattır.
// mongosh içinde
use admin
db.createUser({
user: "yonetici",
pwd: passwordPrompt(),
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
})
use uygulamadb
db.createUser({
user: "uygulama",
pwd: passwordPrompt(),
roles: [ { role: "readWrite", db: "uygulamadb" } ]
})
passwordPrompt() kullanmak, parolanın kabuk geçmişine ve süreç listesine düşmesini engeller. Ardından servisi yeniden başlatın ve uygulamanızın bağlantı dizesini güncelleyin:
mongodb://uygulama:[email protected]:27017/uygulamadb?authSource=uygulamadb
authSource parametresini yazmayı unutmak, doğru parolayla bile kimlik doğrulama hatası almanızın en sık sebebidir: MongoDB kullanıcıyı hangi veritabanında arayacağını bilemez.
Uygulama Sunucusu Ayrı Makinedeyse Ne Yapmalı?#
bind 127.0.0.1 en güvenli ayardır ama uygulama başka bir sunucudaysa çalışmaz. Bu durumda seçenekler, en iyiden en kötüye şu sırayla dizilir:
- Özel ağ arayüzü. Sağlayıcınız sunucular arasında özel ağ veriyorsa servisi yalnızca o arayüzün adresine bağlayın (
bind 10.0.0.5). Trafik genel internete hiç çıkmaz. - WireGuard veya benzeri bir tünel. Sunucular arasında şifreli bir ağ kurar, servisi tünel arayüzüne bağlarsınız. Özel ağı olmayan sağlayıcılarda doğru cevap budur.
- SSH tüneli. Tek uygulama sunucusu için hızlı ve güvenilir bir çözümdür; bağlantı kopmalarına karşı
autosshgibi tüneli ayakta tutan bir araçla desteklenmelidir. - TLS ile doğrudan bağlantı. Redis 6 ve sonrası ile MongoDB, istemci sertifikasıyla TLS destekler. Kurulumu daha zahmetlidir ama uzak bölgeler arası bağlantılar için uygundur.
- Güvenlik duvarında IP kısıtı. En zayıf katmandır ve tek başına kullanılmamalıdır; parola ve şifreleme yerine geçmez. Yine de her zaman eklenmelidir:
sudo ufw allow from 203.0.113.20 to any port 6379 proto tcp
sudo ufw deny 6379/tcp
Kural yazarken sıralamaya dikkat edin. UFW kuralları yukarıdan aşağı değerlendirir; izin kuralı reddetme kuralından sonra eklenirse hiçbir işe yaramaz. Ayrıntılı kural yönetimi için iptables ile güvenlik duvarı yazısına göz atın.
Zaten Saldırıya Uğradıysanız: İlk Saatte Yapılacaklar#
Sırayı bozmayın; en sık yapılan hata, delilleri silerek servisi hemen yeniden başlatmaktır.
- Erişimi kesin. Servisi durdurun veya güvenlik duvarında portu tamamen kapatın. Saldırganın hâlâ bağlı olduğunu varsayın.
- Diski dondurun. Sağlayıcınızda anlık görüntü (snapshot) alın. Bu, hem adli inceleme hem de yanlış bir müdahaleden dönmek için tek şansınızdır.
- Kalıcılık izlerini arayın. Tüm kullanıcıların zamanlanmış görevleri (
crontab -l,/etc/cron.d/,/var/spool/cron/),~/.ssh/authorized_keysdosyaları, yeni sistem kullanıcıları ve tanımadığınız systemd birimleri. - Kaynak tüketimine bakın.
topçıktısında CPU'yu dolduran bilinmeyen süreçler kripto madenci göstergesidir. - Ödeme yapmayın. Verinin gerçekten kopyalandığına dair kanıtınız yoksa ödeme, karşılığı olmayan bir masraftır. Bu kampanyalarda geri dönüş oranı çok düşüktür.
- Yedekten dönün, sunucudan değil. Aynı makineyi temizleyip devam etmek yerine yeni bir sunucu kurup yedekten geri yüklemek çoğu durumda daha hızlı ve daha güvenlidir.
- Tüm kimlik bilgilerini yenileyin. Veritabanı parolaları, API anahtarları, SSH anahtarları ve uygulama sırları. Sunucu ele geçirildiyse hepsi okunmuş sayılır.
Sunucu genelinde temizlik ve arka kapı arayışı için hacklenmiş site kurtarma adımlarını da uygulayın.
Sıkça Sorulan Sorular#
Redis'e parola koydum, portu açık bırakabilir miyim?#
Teknik olarak mümkün ama önerilmez. Redis parolası şifrelenmemiş bir bağlantı üzerinden düz metin gider; ağı dinleyen biri parolayı görebilir. Ayrıca Redis, saniyede çok sayıda komut işleyebildiği için parola deneme saldırılarına açıktır. Portu internete açmak yerine özel ağ, VPN tüneli veya en azından güvenlik duvarında IP kısıtı kullanın; parolayı bunların yerine değil, yanına ekleyin.
UFW'de portu kapattım ama dışarıdan hâlâ erişiliyor. Nasıl olur?#
Neredeyse her zaman Docker sebebidir. Docker, yayınlanan portlar için iptables kurallarını FORWARD zincirine yazar; UFW ise INPUT zincirinde çalışır. Konteynere giden paket UFW kurallarına hiç uğramadan hedefe ulaşır. Çözüm, portu 127.0.0.1:6379:6379 biçiminde yayınlamak, hiç yayınlamamak veya kısıtlamayı DOCKER-USER zincirine yazmaktır.
Sunucumda özel IP yok, uygulama başka bir sağlayıcıda. Ne yapmalıyım?#
Bu senaryoda en pratik çözüm iki sunucu arasında WireGuard tüneli kurmak ve veritabanını yalnızca tünel arayüzünün adresine bağlamaktır. Kurulumu birkaç dakika sürer, trafik şifrelenir ve veritabanı portu genel internette hiç görünmez. Tek uygulama sunucusu için SSH tüneli de kabul edilebilir bir alternatiftir.
Veritabanım silindi ama yedeğim var. Doğrudan geri yükleyebilir miyim?#
Yedeği geri yüklemeden önce sunucunun kendisinin temiz olduğundan emin olun. Açık Redis üzerinden yapılan saldırıların önemli bölümü sunucuda kalıcı erişim veya madenci bırakır; temizlemeden yüklenen veri kısa süre sonra tekrar silinir. Doğru sıra şudur: portu kapat, zamanlanmış görev ve SSH anahtarlarını denetle, mümkünse yeni bir sunucu kur, sonra geri yükle.
Elasticsearch, Memcached ve PostgreSQL için de aynı risk var mı?#
Evet, mantık aynıdır. Memcached hiçbir zaman kimlik doğrulaması sunmaz ve UDP üzerinden yansıtmalı saldırılarda kullanılır. Elasticsearch'in ücretsiz sürümlerinde uzun süre güvenlik varsayılan olarak kapalıydı ve aynı fidye dalgalarına hedef oldu. PostgreSQL ve MySQL parola ister, ancak zayıf parola ve internete açık port birleşimi yine ele geçirilmeye açıktır. Kural değişmez: veritabanı portu internete bakmamalıdır.
Portun açık olup olmadığını sunucunun kendisinden test edebilir miyim?#
Hayır, güvenilir sonuç vermez. Sunucunun kendi üzerinden yapılan bağlantı loopback arayüzünü kullanabilir ve güvenlik duvarı kurallarını atlayabilir. Testi mutlaka başka bir makineden, tercihen farklı bir ağdan yapın. Elinizde ikinci bir sunucu yoksa kendi bilgisayarınızdan nmap -Pn -p 6379 SUNUCU_IP komutu yeterlidir.