មុនពេល Baby Monitor Timmy បញ្ជូនសំឡេង និងវីដេអូ ឧបករណ៍ពីរត្រូវស្វែងរកគ្នា និងទុកចិត្តគ្នាជាមុន។ ជំហាន ផ្គូផ្គង នេះគឺជាពេលវេលាសំខាន់បំផុតក្នុងដំណើរការទាំងមូល។ នៅទីនេះ ខ្ញុំពន្យល់ពីរបៀបដែល Timmy ផ្គូផ្គង បច្ចេកវិទ្យាគ្រីបតូដែលនៅពីក្រោយវា និងហេតុអ្វីអ្នកវាយប្រហារនៅក្បែរមិនអាចគ្រប់គ្រងការភ្ជាប់ដោយគ្មានអ្នកដឹងបាន។
បញ្ហា៖ ឧបករណ៍របស់ខ្ញុំដឹងដូចម្តេចថាវាកំពុងនិយាយជាមួយអ្នកណា?
នៅពេលឧបករណ៍ពីរភ្ជាប់គ្នាជាលើកដំបូង សំណួរសំខាន់គឺ៖ តើឧបករណ៍ A ពិតជាកំពុងនិយាយជាមួយឧបករណ៍ B ឬមាននរណាម្នាក់នៅកណ្ដាល? ក្នុងវិស័យគ្រីបតូ វាត្រូវហៅថា ការវាយប្រហារដោយអ្នកនៅកណ្ដាល (MITM)។
Timmy ដោះស្រាយបញ្ហានេះដោយប្រើ ការផ្លាស់ប្ដូរសោ Elliptic Curve Diffie-Hellman (ECDH) តាម Firebase រួមជាមួយ ការផ្ទៀងផ្ទាត់ដោយភ្នែកពីអ្នកប្រើ.
ដ្យាក្រាមខាងក្រោមបង្ហាញលំហូរផ្គូផ្គងពេញលេញមួយភ្លែត៖
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
លំដាប់ពិធីការផ្គូផ្គងពេញលេញ — ប្រភពអាចកែសម្រួលបាន៖ docs/diagrams/pairing-sequence.mmd
ជំហានទី 1៖ ឧបករណ៍នីមួយៗបង្កើតគូសោ
ពេលបើកអេក្រង់ផ្គូផ្គង ឧបករណ៍នីមួយៗបង្កើត គូសោ ECDH បណ្តោះអាសន្ន លើខ្សែកោង P-256 (secp256r1)៖
- សោ ឯកជន — រក្សាទុកតែលើឧបករណ៍ប៉ុណ្ណោះ
- សោ សាធារណៈ — ផ្លាស់ប្ដូរតាម Firebase
សោទាំងនេះត្រូវបានបង្កើតដោយកម្មវិធីបង្កើតលេខចៃដន្យដែលមានសុវត្ថិភាពតាមគ្រីបតូ (Random.secure())
ហើយ មានសុពលភាពសម្រាប់តែការព្យាយាមផ្គូផ្គងមួយលើកនេះប៉ុណ្ណោះ។ សោថ្មីត្រូវបានបង្កើត
សម្រាប់រាល់ការព្យាយាមថ្មី។
ជំហានទី 2៖ ផ្លាស់ប្ដូរសោសាធារណៈតាម Firebase
ដើម្បីឲ្យឧបករណ៍ពីរស្វែងរកគ្នា Timmy ប្រើ កូដ 4 តួអក្សរ ជាចំណុចជួបគ្នា។ កូដនេះអាចត្រូវបានរកឃើញដោយស្វ័យប្រវត្តិតាម Nearby Connections (Bluetooth Low Energy) ឬបញ្ចូលដោយដៃ។ វា គ្មានតម្លៃផ្នែកគ្រីបតូទេ; វាគ្រាន់តែជួយឲ្យឧបករណ៍ទាំងពីររកឃើញឯកសារ Firebase Firestore ដូចគ្នា។
ពេលឧបករណ៍ទាំងពីរដឹងកូដហើយ ឧបករណ៍នីមួយៗសរសេរសោ ECDH សាធារណៈរបស់ខ្លួនទៅក្នុង ឯកសារ Firestoreរួមមួយ។ បន្ទាប់មក ឧបករណ៍នីមួយៗអានសោសាធារណៈរបស់ឧបករណ៍ម្ខាងទៀតពីឯកសារនោះ។
ចំណុចសំខាន់៖ មានតែសោ សាធារណៈ ប៉ុណ្ណោះដែលត្រូវបានផ្ញើ។ សោឯកជនមិនដែលចេញពីឧបករណ៍ទេ។ អ្នកណាដែលតាមដានចរាចរណ៍ Firebase អាចឃើញសោសាធារណៈ ប៉ុន្តែ មិនអាចគណនាសម្ងាត់រួម ពីសោទាំងនោះបានទេ។ វាផ្អែកលើភាពពិបាកនៃ បញ្ហាលោការីតឌីសគ្រីតលើខ្សែកោងអេលីប (ECDLP)។
ជំហានទី 3៖ គណនាសម្ងាត់រួម
ពេលឧបករណ៍ទាំងពីររកឃើញសោសាធារណៈរបស់គ្នាទៅវិញទៅមក ពួកវាគណនាដោយឯករាជ្យនូវ សម្ងាត់រួម:
sharedSecret = ECDH(myPrivateKey, remotePublicKey)
→ 32 bytes (identical on both devices)
ដូចគ្នា។ គណិតវិទ្យានៃខ្សែកោងអេលីបធានាថាការគណនាទាំងពីរផ្តល់លទ្ធផលដូចគ្នា ទោះបីឧបករណ៍នីមួយៗដឹងតែសោឯកជនរបស់ខ្លួន និងសោសាធារណៈរបស់ម្ខាងទៀតក៏ដោយ។
ជំហានទី 4៖ លេខផ្ទៀងផ្ទាត់ (SAS)
ពីសម្ងាត់រួម ខ្សែអក្សរផ្ទៀងផ្ទាត់ខ្លី (SAS) ត្រូវបានបង្កើតឡើង — ជាលេខពីរខ្ទង់ដែលបង្ហាញលើឧបករណ៍ទាំងពីរ៖
hash = SHA-256("sas:" + sort(pubkeyA, pubkeyB) + sharedSecret)
number = (hash[0] × 256 + hash[1]) mod 100 → 00 to 99
ឧបករណ៍ទាំងពីរបង្ហាញលេខដូចគ្នា — ឧទាហរណ៍ 42។ អ្នកប្រើ ប្រៀបធៀបដោយភ្នែកថាលេខលើអេក្រង់ទាំងពីរត្រូវគ្នាឬអត់ រួចបញ្ជាក់លើ ឧបករណ៍ នីមួយៗដោយឡែកពីគ្នា។
ហេតុអ្វីអ្នកវាយប្រហារមិនអាចក្លែងបន្លំវាបាន
អ្នកវាយប្រហារដែលស្ថិតនៅកណ្ដាលត្រូវស្ទាក់ចាប់ការផ្លាស់ប្តូរសោក្នុង Firebase។ ជាក់លាក់ ពួកគេត្រូវ៖
- ជំនួសសោសាធារណៈពិតដែលរក្សាទុកក្នុងឯកសារ Firestore ដោយសោរបស់ពួកគេ
- បង្កើតសម្ងាត់រួមដាច់ដោយឡែកជាមួយឧបករណ៍នីមួយៗ
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 មិនត្រូវគ្នា — ប្រភពអាចកែសម្រួលបាន៖ docs/diagrams/mitm-detection.mmd
ក្នុងករណីនេះ អ្នកវាយប្រហារគណនាសម្ងាត់រួមមួយ S_A ជាមួយឧបករណ៍ A និង
សម្ងាត់រួមផ្សេង S_B ជាមួយឧបករណ៍ B។ ដោយសារ S_A ≠ S_B ដូច្នេះ
ឧបករណ៍ទាំងពីរគណនា លេខផ្ទៀងផ្ទាត់ខុសគ្នា.
។ អ្នកវាយប្រហារមិនអាចធ្វើឲ្យលេខទាំងនោះត្រូវគ្នាបានទេ ពីព្រោះ៖
- ពួកគេមិនដឹងសោឯកជនរបស់ឧបករណ៍ទេ
- SHA-256 មិនអាចបញ្ច្រាសបានទេ
- ឱកាសដែលលេខត្រូវគ្នាដោយចៃដន្យមានតែ 1 ក្នុងចំណោម 100
។ អ្នកប្រើឃើញលេខខុសគ្នាលើអេក្រង់ ហើយបោះបង់ការផ្គូផ្គង។ នៅពេលនោះ ការវាយប្រហារត្រូវបានបង្ហាញឲ្យដឹង។
ជំហានទី 5៖ បញ្ចប់ការផ្គូផ្គង
លុះត្រាតែអ្នកប្រើបញ្ជាក់ការផ្ទៀងផ្ទាត់លើ ឧបករណ៍ទាំងពីរ ទើប ការផ្គូផ្គងបញ្ចប់៖
- សោ ផ្គូផ្គង 64 តួអក្សរ (256 ប៊ីត) ត្រូវបានបង្កើតពីសម្ងាត់រួម៖
SHA-256("pair:" + sharedSecret) → pairingKey - សោឯកសារត្រូវបានបង្កើតជា
SHA-256("doc:" + pairingKey)ហើយប្រើជាសោឯកសារ Firestore - សោអ៊ិនគ្រីបត្រូវបានបង្កើតជា
SHA-256("enc:" + pairingKey)ហើយផ្តល់សោ AES-256-GCM សម្រាប់ការផ្តល់សញ្ញាដែលបានអ៊ិនគ្រីប - ឧបករណ៍ទាំងពីររក្សាទុកសោផ្គូផ្គងដូចគ្នា ហើយបន្តទៅការជ្រើសរើសរបៀប
ចាប់ពីចំណុចនេះទៅ ការព្យាយាមភ្ជាប់បន្តទៀតទាំងអស់ (ការផ្តល់សញ្ញា Firestore ការរៀបចំ WebRTC) ត្រូវបានអ៊ិនគ្រីបដោយសោ AES-256-GCM រួម។ សោផ្គូផ្គង មិនដែលត្រូវផ្ញើទៅ backendទេ; មានតែ hash SHA-256 របស់វាប៉ុណ្ណោះដែលត្រូវប្រើជាលេខសម្គាល់ឯកសារ។
ស្ថាបត្យកម្មប្រព័ន្ធ
ដ្យាក្រាមខាងក្រោមបង្ហាញសមាសភាគដែលពាក់ព័ន្ធនឹងការផ្គូផ្គង និងការទំនាក់ទំនង៖
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
ទិដ្ឋភាពទូទៅស្ថាបត្យកម្មប្រព័ន្ធ — ប្រភពអាចកែសម្រួលបាន៖ docs/diagrams/pairing-architecture.mmd
ផ្លូវទំនាក់ទំនងលម្អិត៖
- WebRTC ពីឧបករណ៍ទៅឧបករណ៍ (បន្ទាត់ក្រាស់)៖ សំឡេង វីដេអូ និង DataChannel ហូរដោយផ្ទាល់ រវាងឧបករណ៍ — អ៊ិនគ្រីបដោយ DTLS-SRTP។ គ្មានម៉ាស៊ីនមេណាឃើញទិន្នន័យនេះទេ។
- Firebase Firestore (បន្ទាត់ពេញ)៖ ទិន្នន័យផ្គូផ្គង (សោ ECDH) និងការផ្តល់សញ្ញា (SDP/ICE) ឆ្លងកាត់ Firestore — អ៊ិនគ្រីបពីចុងដល់ចុងដោយ AES-256-GCM។ Firebase មិនអាចឌិគ្រីបទិន្នន័យបានទេ។
- ម៉ាស៊ីនមេ STUN: ឧបករណ៍ទាំងពីរស្វែងរកអាសយដ្ឋាន IP សាធារណៈរបស់ខ្លួន ដើម្បីអាចបង្កើត ការភ្ជាប់ពីឧបករណ៍ទៅឧបករណ៍ដោយផ្ទាល់។
- TURN relay: ប្រសិនបើការភ្ជាប់ដោយផ្ទាល់មិនអាចធ្វើបាន (ឧ. ពេលប្រើ ទិន្នន័យចល័ត) ម៉ាស៊ីនមេ TURN ក្នុងតំបន់ដែលបានជ្រើស ឬ Cloudflare TURN នឹងបញ្ជូនមេឌៀដែលបានអ៊ិនគ្រីបបន្ត។ ព័ត៌មានសម្គាល់រយៈពេលខ្លី (24 ម៉ោង) ត្រូវបានទាញយក តាម Firebase Cloud Functions។
- Bluetooth LE (បន្ទាត់ចុចៗ)៖ Nearby Connections រកឃើញឧបករណ៍នៅក្បែរ ដោយស្វ័យប្រវត្តិ — មានតែកូដសម្រាប់ជួបគ្នាប៉ុណ្ណោះដែលត្រូវបានបញ្ជូន មិនមានទិន្នន័យសោឡើយ។
ជម្រើសបម្រុង៖ បញ្ចូលកូដដោយដៃ
បើ Bluetooth មិនមាន (ឧ. លើឧបករណ៍ចាស់ៗ) កូដ 4 តួអក្សរក៏អាចវាយបញ្ចូលដោយដៃបានដែរ។ ការបញ្ចូលដោយដៃប្រើ ការផ្លាស់ប្ដូរសោ ECDH ដូចគ្នា និងការផ្ទៀងផ្ទាត់ SAS ដូចគ្នា ដូចការផ្គូផ្គងស្វ័យប្រវត្តិ។ ភាពខុសគ្នាតែមួយគត់គឺអ្នកប្រើអាន និងវាយបញ្ចូលកូដ ជំនួសឲ្យរកឃើញវាតាម BLE។
ដោយសារការផ្លាស់ប្ដូរសោ ECDH កើតឡើងតាម Firebase ក្នុងករណីទាំងពីរ សុវត្ថិភាពគឺ ដូចគ្នា។ កូដ 4 តួអក្សរគ្រាន់តែជាចំណុចជួបគ្នា; ការអ៊ិនគ្រីបពិតប្រាកដផ្អែកលើសោ 256 ប៊ីតដែលបង្កើតពី ECDH។
សរុប
| យន្តការសុវត្ថិភាព | ការពារប្រឆាំងនឹង |
|---|---|
| ការផ្លាស់ប្ដូរសោ ECDH (P-256) | ការលួចស្តាប់ចរាចរណ៍ផ្លាស់ប្ដូរសោ |
| គូសោបណ្តោះអាសន្ន | Forward secrecy — ការផ្គូផ្គងពីមុននៅតែមានសុវត្ថិភាព |
| លេខផ្ទៀងផ្ទាត់ដោយភ្នែក (SAS) | អ្នកវាយប្រហារបុរសនៅកណ្ដាល (MITM) ពេលផ្លាស់ប្ដូរសោ |
| hash SHA-256 ជាសោឯកសារ | ការទាញយកកូដពី Firestore |
| ការអ៊ិនគ្រីប AES-256-GCM | ការលួចស្តាប់ទិន្នន័យផ្តល់សញ្ញា |
| ការបញ្ជាក់ពីភាគីទាំងពីរ | ការផ្គូផ្គងម្ខាងឯងដោយគ្មានអ្នកប្រើដឹង |
| DTLS-SRTP (WebRTC) | ការលួចស្តាប់សំឡេង/វីដេអូ |
ស្រទាប់ទាំងនេះបំពេញគ្នា៖ ECDH ការពារការផ្លាស់ប្ដូរសោ លេខផ្ទៀងផ្ទាត់ការពារប្រឆាំង MITM, AES-256-GCM ការពារការផ្តល់សញ្ញា ហើយ WebRTC ការពារមេឌៀ។ អ្នកវាយប្រហារត្រូវបំបែកខ្សែសង្វាក់នេះនៅច្រើនកន្លែង ដោយគ្មានឧបករណ៍ ឬឪពុកម្តាយដឹង។