Baby Monitor Timmy ses ve görüntü iletmeye başlamadan önce iki cihazın birbirini bulması ve birbirine güvenmesi gerekir. Bu eşleştirme adımı, tüm sürecin en kritik anıdır. Burada Timmy'nin nasıl eşleştiğini, bunun arkasındaki kriptografiyi ve yakındaki bir saldırganın bağlantıyı fark edilmeden neden ele geçiremeyeceğini açıklıyorum.
Sorun: Cihazım kiminle konuştuğunu nasıl biliyor?
İki cihaz ilk kez bağlandığında temel soru şudur: A Cihazı gerçekten B Cihazıyla mı konuşuyor, yoksa araya biri mi giriyor? Kriptografide buna ortadaki adam saldırısı (MITM) denir.
Timmy bunu, Firebase üzerinden Eliptik Eğri Diffie-Hellman (ECDH) anahtar değişimi ve kullanıcının görsel doğrulamasını.
bir araya getirerek çözer. Aşağıdaki diyagram, eşleştirme akışının tamamını bir bakışta gösterir:
sequenceDiagram
autonumber
participant A as 📱 Device A
participant F as ☁️ Firebase
participant B as 📱 Device B
Note over A,B: Phase 1 — Discovery
A->>A: Generate ECDH key pair (P-256)
B->>B: Generate ECDH key pair (P-256)
alt Auto-Pairing (Nearby BLE)
A-->>B: BLE broadcast: SBM:XKQM
B-->>A: BLE broadcast: SBM:R7NP
Note over A,B: Lower code wins → determines creator/joiner
else Manual Pairing
A->>A: Display 4-char code
Note right of A: User reads code
B->>B: User enters code
end
Note over A,B: Phase 2 — ECDH Key Exchange
A->>F: Write public key (PubA) to meeting doc
B->>F: Write public key (PubB) to meeting doc
F-->>B: Read PubA
F-->>A: Read PubB
Note over A,B: Phase 3 — Shared Secret
A->>A: sharedSecret = ECDH(privA, PubB)
B->>B: sharedSecret = ECDH(privB, PubA)
Note over A,B: Both compute identical 32-byte secret
A->>A: SAS = SHA-256("sas:" + sort(PubA,PubB) + secret) → 2-digit number
B->>B: SAS = SHA-256("sas:" + sort(PubA,PubB) + secret) → 2-digit number
Note over A,B: Phase 4 — Visual Verification
A->>A: Display SAS: 42
B->>B: Display SAS: 42
Note over A,B: 👤 User compares numbers on both screens
A->>A: User confirms ✓
B->>B: User confirms ✓
Note over A,B: Phase 5 — Key Derivation
A->>A: pairingKey = SHA-256("pair:" + secret)
B->>B: pairingKey = SHA-256("pair:" + secret)
A->>A: docKey = SHA-256("doc:" + pairingKey)
A->>A: encKey = SHA-256("enc:" + pairingKey)
Note over A,B: ✅ Paired — all future signaling encrypted with AES-256-GCM
Eşleştirme protokolünün tam sırası — düzenlenebilir kaynak: docs/diagrams/pairing-sequence.mmd
1. Adım: Her cihaz bir anahtar çifti oluşturur
Eşleştirme ekranı açıldığında, her cihaz geçici bir ECDH anahtar çifti oluşturur; bu anahtar çifti P-256 eğrisindedir (secp256r1):
- Bir özel anahtar — yalnızca cihazda kalır
- Bir açık anahtar — Firebase üzerinden paylaşılır
Anahtarlar, kriptografik olarak güvenli bir rastgele sayı üreteciyle (Random.secure())
oluşturulur ve yalnızca bu tek eşleştirme denemesi için geçerlidir. Her yeni deneme için yeni anahtarlar oluşturulur.
2. Adım: Açık anahtarların Firebase üzerinden paylaşılması
Timmy, iki cihazın birbirini bulmasını sağlamak için buluşma noktası olarak 4 karakterli bir kod kullanır. Bu kod Nearby Connections (Bluetooth Low Energy) aracılığıyla otomatik bulunabilir veya elle girilebilir. Kodun kriptografik bir değeri yoktur; yalnızca iki cihazın aynı Firebase Firestore belgesini bulmasını sağlar.
Her iki cihaz da kodu öğrendiğinde, her biri açık ECDH anahtarını ortak bir Firestore belgesineyazar. Ardından her cihaz, diğer cihazın açık anahtarını bu belgeden okur.
Önemli nokta: yalnızca açık anahtar gönderilir. Özel anahtar cihazdan asla ayrılmaz. Firebase trafiğini izleyen biri açık anahtarları görür, ancak bunlardan ortak gizli değeri hesaplayamaz . Bu, Eliptik Eğri Ayrık Logaritma Problemi'nin (ECDLP) zorluğuna dayanır.
3. Adım: Ortak gizli değerin hesaplanması
Her iki cihaz da birbirinin açık anahtarını edindiğinde, birbirinden bağımsız olarak aynı ortak gizli değeri hesaplar.:
sharedSecret = ECDH(myPrivateKey, remotePublicKey)
→ 32 bytes (identical on both devices)
Eliptik eğri matematiği, her cihaz yalnızca kendi özel anahtarını ve diğer cihazın açık anahtarını bilmesine rağmen iki hesaplamanın da aynı sonucu vermesini garanti eder.
4. Adım: Doğrulama numarası (SAS)
Paylaşılan gizden bir Kısa Kimlik Doğrulama Dizisi (SAS) türetilir — her iki cihazda da gösterilen iki basamaklı bir sayı:
hash = SHA-256("sas:" + sort(pubkeyA, pubkeyB) + sharedSecret)
number = (hash[0] × 256 + hash[1]) mod 100 → 00 to 99
Her iki cihaz da aynı sayıyı gösterir — örneğin, 42. Kullanıcı, her iki ekrandaki sayıların eşleşip eşleşmediğini görsel olarak karşılaştırır ve ardından her cihazda ayrı ayrı onaylar.
Bir saldırgan bunu neden taklit edemez
Ortadaki adam saldırganının Firebase'teki anahtar değişimini ele geçirmesi gerekir. Bunun için şunları yapması gerekir:
- Firestore belgesinde saklanan gerçek açık anahtarları kendi açık anahtarlarıyla değiştirmek
- Her cihazla ayrı paylaşılan gizler oluşturmak
sequenceDiagram
autonumber
participant A as 📱 Device A
participant M as 🕵️ Attacker (MITM)
participant B as 📱 Device B
Note over A,B: Attacker intercepts the Firebase key exchange
A->>A: Generate key pair (privA, PubA)
B->>B: Generate key pair (privB, PubB)
M->>M: Generate TWO key pairs (privM1, PubM1) + (privM2, PubM2)
A->>M: Write PubA to Firebase
M->>M: Replace PubA with PubM1
M->>B: B reads PubM1 (thinks it is PubA)
B->>M: Write PubB to Firebase
M->>M: Replace PubB with PubM2
M->>A: A reads PubM2 (thinks it is PubB)
Note over A,B: Each device computes a DIFFERENT shared secret
A->>A: secret_A = ECDH(privA, PubM2)
M->>M: secret_A = ECDH(privM2, PubA)
M->>M: secret_B = ECDH(privM1, PubB)
B->>B: secret_B = ECDH(privB, PubM1)
Note over A,M: secret_A ≠ secret_B
A->>A: SAS_A = SHA-256("sas:" + sort(PubA,PubM2) + secret_A) → 73
B->>B: SAS_B = SHA-256("sas:" + sort(PubM1,PubB) + secret_B) → 18
rect rgb(255, 230, 230)
Note over A,B: ❌ User sees DIFFERENT numbers!
A->>A: Display: 73
B->>B: Display: 18
Note over A,B: 👤 User notices mismatch → cancels pairing
end
Note over A,B: 🛡️ Attack detected — MITM cannot force SAS match (P = 1/100)
SAS uyuşmazlığıyla ortadaki adam saldırısının tespiti — düzenlenebilir kaynak: docs/diagrams/mitm-detection.mmd
Bu durumda saldırgan, S_A A Cihazıyla bir ortak gizli değer, B Cihazıyla ise farklı bir ortak gizli değer S_B hesaplar. Çünkü S_A ≠ S_B,
cihazlar farklı doğrulama numaraları hesaplar..
Saldırgan sayıların eşleşmesini sağlayamaz, çünkü:
- Cihazların özel anahtarlarını bilmez
- SHA-256 tersine çevrilemez
- Rastgele eşleşme olasılığı yalnızca 100'de 1
Kullanıcı ekranlarda farklı sayılar görür ve eşleştirmeyi iptal eder. Bu noktada saldırı görünür hâle gelmiştir.
Adım 5: Eşleştirmenin tamamlanması
Yalnızca kullanıcı her iki cihazda doğrulamayı onayladıktan sonra eşleştirme tamamlanır:
- Bir 64 karakterlik eşleştirme anahtarı (256 bit) paylaşılan gizden türetilir:
SHA-256("pair:" + sharedSecret) → pairingKey - Belge anahtarı
SHA-256("doc:" + pairingKey)olarak türetilir ve Firestore belge anahtarı olarak kullanılır - Şifreleme anahtarı
SHA-256("enc:" + pairingKey)olarak türetilir ve şifrelenmiş sinyalleşme için AES-256-GCM anahtarını sağlar - Her iki cihaz aynı eşleştirme anahtarını saklar ve mod seçimine geçer
Bu noktadan itibaren tüm bağlantı denemeleri (Firestore sinyalleşmesi, WebRTC kurulumu) paylaşılan AES-256-GCM anahtarıyla şifrelenir. Eşleştirme anahtarı asla arka uca gönderilmez; yalnızca SHA-256 özeti belge tanımlayıcısı olarak kullanılır.
Sistem mimarisi
Aşağıdaki diyagram, eşleştirme ve iletişimde yer alan bileşenleri gösterir:
flowchart TB
BABY["📱 Baby Phone
Baby Mode"]
PARENT["📱 Parent Phone
Parent Mode"]
BABY <==>|"🔒 WebRTC Peer-to-Peer · DTLS-SRTP
Audio · Video · DataChannel"| PARENT
BABY -.-|"🔵 Bluetooth LE · Nearby
Auto-Discovery"| PARENT
subgraph FIREBASE["☁️ Firebase (Google Cloud)"]
direction LR
AUTH["🪪 Anonymous
Authentication"]
FS["📄 Firestore
Pairing + Signaling"]
CF["⚡ Cloud Functions
getTurnCredentials"]
end
BABY <-->|"🔐 AES-256-GCM encrypted
SDP · ICE · ECDH keys"| FS
FS <-->|"🔐 AES-256-GCM encrypted
SDP · ICE · ECDH keys"| PARENT
BABY -.->|Token| AUTH
PARENT -.->|Token| AUTH
STUN["📡 STUN server
stun.cloudflare.com:3478"]
TURN["🔄 TURN relay
local or Cloudflare"]
BABY & PARENT -->|Short-lived credentials| CF
CF -->|local first, Cloudflare fallback| TURN
BABY & PARENT -.->|NAT Traversal| STUN
BABY -.->|"Relay Fallback"| TURN
TURN -.->|"Relay Fallback"| PARENT
style BABY fill:#FBF6F0,stroke:#B5734A,stroke-width:2px
style PARENT fill:#FBF6F0,stroke:#B5734A,stroke-width:2px
style FIREBASE fill:#fff5f5,stroke:#E9B44C,stroke-width:2px
style AUTH fill:#E9B44C,stroke:#2B2D42
style FS fill:#E9B44C,stroke:#2B2D42
style CF fill:#E9B44C,stroke:#2B2D42
style STUN fill:#F6E3D2,stroke:#B5734A
style TURN fill:#7BC47F,stroke:#2B2D42
Sistem mimarisine genel bakış — düzenlenebilir kaynak: docs/diagrams/pairing-architecture.mmd
İletişim yollarının ayrıntıları:
- WebRTC eşler arası (kalın çizgi): Ses, video ve DataChannel doğrudan cihazlar arasında akar — DTLS-SRTP ile şifrelenir. Hiçbir sunucu bu verileri görmez.
- Firebase Firestore (düz çizgi): Eşleştirme verileri (ECDH anahtarları) ve sinyalleşme (SDP/ICE) Firestore üzerinden gider — AES-256-GCM ile uçtan uca şifrelenir. Firebase verilerin şifresini çözemez.
- STUN sunucusu: Her iki cihaz, doğrudan eşler arası bağlantı kurulabilmesi için genel IP adresini öğrenir.
- TURN aktarıcısı: Doğrudan bağlantı mümkün değilse (örneğin mobil veride), seçilen yerel veya Cloudflare TURN sunucusu şifrelenmiş medyayı aktarır. Kısa süreli kimlik bilgileri (24 saat), Firebase Cloud Functions üzerinden alınır.
- Bluetooth LE (noktalı çizgi): Nearby Connections yakındaki cihazları otomatik olarak bulur — yalnızca buluşma kodu iletilir, hiçbir anahtar verisi aktarılmaz.
Alternatif: Kodu elle girme
Bluetooth kullanılamıyorsa (örneğin eski cihazlarda), 4 karakterli kod elle de girilebilir. Elle girişte aynı ECDH anahtar değişimi ve aynı SAS doğrulaması otomatik eşleştirmedeki gibi kullanılır. Tek fark, kodun BLE ile bulunması yerine kullanıcı tarafından okunup yazılmasıdır.
Her iki durumda da ECDH anahtar değişimi Firebase üzerinden gerçekleştiği için güvenlik aynıdır. 4 karakterli kod yalnızca bir buluşma noktasıdır; asıl şifreleme ECDH'den türetilen 256 bitlik anahtara dayanır.
Özet
| Güvenlik mekanizması | Koruduğu tehdit |
|---|---|
| ECDH anahtar değişimi (P-256) | Anahtar değişimi trafiğinin dinlenmesi |
| Geçici anahtar çiftleri | İleriye dönük gizlilik — geçmiş eşleştirmeler güvende kalır |
| Görsel doğrulama numarası (SAS) | Anahtar değişimi sırasında ortadaki adam saldırısı (MITM) |
| Belge anahtarı olarak SHA-256 özeti | Firestore'dan kod çıkarılması |
| AES-256-GCM şifrelemesi | Sinyalleşme verilerinin dinlenmesi |
| İki taraflı onay | Kullanıcı bilgisi olmadan tek taraflı eşleştirme |
| DTLS-SRTP (WebRTC) | Ses/video dinleme |
Bu katmanlar birlikte çalışır: ECDH anahtar değişimini, doğrulama numarası MITM saldırılarını, AES-256-GCM sinyalleşmeyi ve WebRTC medyayı korur. Bir saldırganın, cihazlar veya ebeveynler fark etmeden bu zinciri birkaç noktada kırması gerekir.