medicus.global · 2026-05-05
"Tüm bilgileri ben kendim girdim ve acil yardım ekiplerinin ve
doktorların bunları okuyabilmesine onay veriyorum — onlara kişisel
durumum hakkında mümkün olan en iyi ön bilgiyi sağlamak için,
özellikle bir acil durumda. Hayata olan sevgim, ülkenin veri
koruma kurallarından daha büyük."
Bu, oluşturulan her My Medicus profilinin arkasındaki yetişkin, gönüllü karardır. Görevimiz hastanın seçimini onurlandırmaktır: verileri güvenli şekilde saklamak, sadece doğru PIN'e sahip olana göstermek, hastanın her taramayı görmesine izin vermek ve kart kaybedildiği saniye hastanın kartı iptal etmesine izin vermek. Bu belgenin geri kalanı nasıl olduğunu açıklar.
"My Medicus ile ilgili güvenliğiniz nedir?"
Bir acil durumda, hastanın en büyük arzusu iyileşmektir. Hizmet ettiğimiz odur. Güvenlik araçtır, amaç değil.
Üç ilke her şeyin üstündedir:
My Medicus'a karşı 19 farklı saldırı senaryosu belgeledik ve her birini üretim sistemine karşı çalıştırdık. Sonuç aşağıda anlatılmıştır — pazarlama dili olmadan, "sektör standardı" olmadan, "best practice" olmadan. Sadece somut olarak test edileni.
Canlı veritabanındaki iki hesaba karşı 19 saldırı senaryosu — bir demo hesap ve gerçek yeni bir kullanıcı. Araçlar: doğrudan HTTP istekleri, paralel yürütme, üretim veritabanının SQL incelemesi, yanıt ayrıştırma.
Sonuç: 14 saldırı dayanan savunmalarla karşılaştı. 5 zayıf nokta bulundu ve aynı gün kapatıldı.
| Saldırı | Saldırı neden başarısız oldu |
|---|---|
| Tüm veritabanının çalınması | Alerjiler, ilaçlar, ulusal kimlikler, pasaport, EHIC ve sigorta numaraları AES-256-GCM ile şifrelenir. Anahtar ayrı bir gizli depoda yaşar, asla veritabanında değil. DB dosyasını çalarsanız, okunamayan metin alırsınız |
| 6 haneli PIN'e brute-force | İlerlemeli gecikmeler 5. hatalı denemede devreye girer: 5 sn → 30 sn → 60 sn arasında |
| Login formuna SQL injection | Tüm veritabanı sorguları parametreli sorgu kullanır — beş farklı injection payload reddedildi |
| Login olmadan doğrudan API çağrıları | Tüm korumalı endpoint'ler HTTP 401 döner |
| Token tahmini | Token'lar SHA-256 ile türetilen 32 hex karakterdir. Arama uzayı: 16^32. 50 rastgele deneme → 0 isabet |
| Backup veya config'e path-traversal | /_db_backups/, /.env, /.git, /medicus.db, /wp-config.php hepsi 404 döner |
| "Şifremi unuttum" yoluyla email enumerasyonu | Email var olsun olmasın tutarlı genel cevap — bilgi sızıntısı yok |
| Genel alanlarda XSS | Sunucu hatalı girişi reddeder, HTML/JS yansıması yok |
| Kart PIN'i olmadan fiziksel cüzdan hırsızlığı | PIN kilidi tüm yanlış denemeleri durdurur |
| 10 paralel brute-force denemesi | Rate-limit istek başına değil, token başına uygulanır |
| DELETE endpoint'i ile denetim kaydının silinmesi | DELETE endpoint'i açık değil |
Admin-token tahmini (admin, 1234, letmein) |
Hepsi 401 döner |
| Hata payload'ları ile sunucuya sır sızdırmaya çalışmak | Ne şifreleme anahtarı ne de Stripe sırları hata çıktısında görünür |
| Başka bir siteden cross-origin istismarı | Tarayıcı same-origin politikası nedeniyle engeller |
| # | Ne | Şiddet | Ne yapıldı |
|---|---|---|---|
| F1 | Login, email kayıtlıysa kayıtsız olduğundan 200 ms daha yavaş yanıt veriyordu. Bir saldırgan bir hesabın var olup olmadığını belirleyebilirdi | 🔴 Kritik | Login artık her zaman Argon2id doğrulaması çalıştırır (bilinmeyen email'lere karşı da, dummy hash ile). Sabit yanıt süresi. Genel hata mesajı |
| F2 | Güvenlik başlıkları yok (HSTS, CSP, X-Frame, X-Content-Type, Referrer-Policy, Permissions-Policy) | 🔴 Kritik | 6 başlığın tümü artık middleware aracılığıyla tüm yanıtlara eklenir. CSP script/img/style/frame'i whitelist'e alınmış kaynaklara kilitler |
| F3 | Çalınan bir kartın üzerinde QR + PIN doğrudan basılıdır. Hırsız sahibinin iptal etmesine kadar erişime sahiptir | 🟠 Yüksek | (1) Hasta her taramayı kendi panelinde görür ("Kayıtlarım" — IP öneki, ülke, zaman). (2) Sahibi tek tıkla kartı iptal edebilir → tüm eski basılı kartlar anında ölür + yeni PIN üretilir |
| F4 | /admin herkese SPA-HTML döndürüyordu, bu admin panelinin varlığını ortaya çıkarıyordu |
🟡 Düşük | Artık kimliği doğrulanmamış kullanıcılar için var olmayan rotalarla aynı 404'ü döner |
| F5 | Şifremi-unuttum bir hedefin gelen kutusunu doldurmak için kötüye kullanılabilirdi (1.000 reset mail/saat) — ve aynı zamanda kendi gönderici itibarımıza zarar verebilirdi | 🟠 Yüksek | Kullanıcının geçerli bir reset token'ı varsa (max 2 saat eski), yeni mail göndermek yerine yeniden kullanılır. Plus email başına 2/dk rate-limit |
| Seçim | Gerekçe |
|---|---|
| Sağlıkçı görünümünde ulusal kimlik doğrulaması yok | Hasta golf sahasında bilinçsiz yatıyor. Sağlıkçının ulusal kimliği yok, olsa bile onu giriş yapmak için 90 saniyemiz yok. Kart üzerindeki PIN pratik cevap |
| "Zero-knowledge" değil | Sunucu alanları çözebilir — sağlıkçının veriyi görebilmesi için koşul. Olmadığı bir şeye "zero-knowledge" demiyoruz |
| Otomatik veri içe aktarma yok | Her alan kullanıcı tarafından seçilir. Diğer sağlık platformlarından otomatik içe aktarma yok |
Bir sağlıkçı kartı doğru PIN ile meşru olarak tararsa, ekranı fotoğraflayabilir. Bunu engelleyemeyiz — verinin acil durumda gösterilebilmesinin bedeli budur. Savunma:
Bu, diyabetiklerdeki fiziksel medikal kimlik bilekliği ile aynı güvenlik modelidir: veriler sağlık ekiplerine görünürdür, bir yankesicinin de onları görebileceğini kabul ediyoruz. Fark, bizim modelimizin hastaya kim neyi ne zaman görür üzerinde kontrol vermesidir — sadece görünürlük değil.
Sorular? peter@medicus.global adresine yazın