11.13. การจับคู่และการผูกพัน¶
ทุกอย่างที่กล่าวถึงมาจนถึงตอนนี้จะส่งข้อมูลผ่านคลื่นวิทยุแบบเปิดเผย ผู้ใดก็ตามที่มีแล็ปท็อปที่รองรับ BLE อยู่ในห้องเดียวกันสามารถดักฟังบนช่องโฆษณา ติดตามลำดับการกระโดดของการเชื่อมต่อแบบเปิด และอ่านทุกการอ่าน การเขียน และการแจ้งเตือนที่ผ่านไปได้ สำหรับข้อมูล sensor สาธารณะส่วนใหญ่ (ระดับแบตเตอรี่ อุณหภูมิแวดล้อม) นั่นก็ไม่เป็นปัญหา แต่สำหรับสิ่งที่ทั้งสองฝ่ายต้องการเก็บเป็นความลับ -- รีจิสเตอร์ควบคุมที่เปิดใช้รีเลย์ รหัสผ่าน ข้อมูลที่ไม่ควรเผยแพร่อย่างกว้างขวาง -- ลิงก์จำเป็นต้องเข้ารหัส และในอุดมคติกล้องต้องรู้ว่ากำลังคุยกับ ใคร
BLE รองรับทั้งสองอย่างผ่าน การจับคู่ และ การผูกพัน
11.13.1. การจับคู่ การผูกพัน การเข้ารหัส¶
สามแนวคิดที่เกี่ยวข้องกันอย่างใกล้ชิด:
การเข้ารหัส คือเป้าหมายหลัก เมื่อลิงก์ถูกเข้ารหัสแล้ว ทุกแพ็กเก็ตบนช่องข้อมูลจะสามารถถอดรหัสได้เฉพาะโดยทั้งสองฝ่าย ผู้ดักฟังจะเห็นแต่สัญญาณรบกวน
การจับคู่ คือขั้นตอนที่ทั้งสองฝ่ายดำเนินการ เพื่อตกลงกันเกี่ยวกับคีย์ ที่ใช้ในการเข้ารหัส มันเป็นการแลกเปลี่ยนครั้งเดียวที่ผลิตวัสดุคีย์ที่ใช้ร่วมกันซึ่งเลเยอร์ลิงก์นำไปใส่ในเครื่องมือเข้ารหัส
การผูกพัน คือการเลือกที่จะ จัดเก็บ คีย์ไปยังหน่วยเก็บข้อมูลที่ไม่ลบเลือนหลังจากการจับคู่เสร็จสิ้น เพื่อให้การเชื่อมต่อครั้งถัดไประหว่างอุปกรณ์สองเครื่องเดิมสามารถข้ามการจับคู่และไปสู่การเข้ารหัสได้โดยตรง
ภาษาง่ายๆ: การจับคู่คือ "แนะนำตัวเอง"; การผูกพันคือ "จดจำการแนะนำนี้"; การเข้ารหัสคือ "พูดคุยกันอย่างเป็นความลับตั้งแต่นี้เป็นต้นไป"
ขั้นตอนการจับคู่บนการเชื่อมต่อ BLE แบบเปิด เมื่อการแลกเปลี่ยนคีย์เสร็จสมบูรณ์ เลเยอร์ลิงก์จะเข้ารหัสทุกแพ็กเก็ตที่ตามมา การผูกพันเป็นขั้นตอนเพิ่มเติมในการเขียนคีย์ไปยังแฟลช¶
11.13.2. LE Secure Connections¶
การแลกเปลี่ยนคีย์สมัยใหม่ที่ใช้โดย BLE คือ LE Secure Connections ซึ่งสร้างบน Elliptic Curve Diffie-Hellman ทั้งสองฝ่ายสร้างคู่คีย์ชั่วคราว แลกเปลี่ยนครึ่งส่วนสาธารณะ และรวมผลลัพธ์กับคีย์ส่วนตัวของตนเองเพื่อได้มาซึ่งความลับร่วมกัน -- ความลับที่ผู้ดักฟังไม่สามารถคำนวณได้แม้จะมีบันทึกการแลกเปลี่ยนทั้งหมด
วิธี LE Legacy แบบเก่าปลอดภัยน้อยกว่า (ผู้ดักฟังที่มีการแลกเปลี่ยนทั้งหมดมักจะกู้คืนคีย์ได้) และมีอยู่เพียงเพื่อความเข้ากันได้กับอุปกรณ์ต่อพ่วงเก่า ค่าเริ่มต้นของ aioble คือวิธีสมัยใหม่ (le_secure=True); ให้เก็บไว้อย่างนั้น
11.13.3. การเริ่มต้นการจับคู่¶
central จับคู่โดยการเรียก aioble.DeviceConnection.pair() บนการเชื่อมต่อที่เปิดอยู่แล้ว:
async with await device.connect() as connection:
await connection.pair(bond=True, le_secure=True, mitm=False)
# ... GATT work, now over an encrypted link ...
หลังจาก pair คืนค่า แอตทริบิวต์ encrypted, authenticated, bonded และ key_size บนการเชื่อมต่อจะสะท้อนสิ่งที่ได้เจรจา
อาร์กิวเมนต์คีย์เวิร์ดที่มีประโยชน์ที่สุดสี่ประการ:
bond=True-- บันทึกคีย์ที่ได้ไปยังแฟลชเพื่อให้การเชื่อมต่อครั้งถัดไประหว่างอุปกรณ์สองเครื่องเดิมข้ามขั้นตอนการจับคู่ ค่าเริ่มต้นคือTruele_secure=True-- ใช้ LE Secure Connections ค่าเริ่มต้นคือTrueอย่าเปลี่ยนmitm=False-- ว่าจะต้องการการป้องกัน man-in-the-middle หรือไม่ สิ่งนี้ต้องการช่องทางนอกแบนด์ (รหัสตัวเลขที่แสดงด้านหนึ่งและยืนยันด้านอื่น รหัสผ่านที่พิมพ์เข้า ...) เพื่อให้ผู้ใช้สามารถยืนยันว่าอุปกรณ์สองเครื่องในขั้นตอนการจับคู่เป็นเครื่องที่พวกเขาคิดจริงๆ ค่าเริ่มต้นคือFalse(ไม่มีการป้องกัน MITM -- ผู้ดักฟังเฉยๆ ไม่สามารถอ่านลิงก์ได้ แต่ผู้โจมตีที่เปลี่ยนเส้นทางการเชื่อมต่ออย่างแข็งขันอาจจับคู่ตัวเองเข้ามาได้) ตั้งค่าเป็นTrueสำหรับสิ่งที่ละเอียดอ่อน แต่โปรดทราบว่ามันต้องการให้อุปกรณ์ต่อพ่วงรองรับความสามารถ IO จริงๆio=3-- ความสามารถ IO ที่อุปกรณ์อ้างสิทธิ์ ข้อกำหนด Bluetooth กำหนดห้าแบบ:0แสดงผลเท่านั้น,1แสดงผล + ใช่/ไม่ใช่,2คีย์บอร์ดเท่านั้น,3ไม่มีอินพุตไม่มีเอาต์พุต,4คีย์บอร์ด + แสดงผล กล้องที่ไม่มี UI มักรายงาน3; ถ้ากล้องเองมีจอแสดงผล แอปพลิเคชันสามารถแสดงการยืนยันตัวเลขและใช้1การรวมความสามารถ IO ของทั้งสองฝ่ายจะตัดสินว่าการป้องกัน MITM จริงๆ ทำได้หรือไม่
อุปกรณ์ต่อพ่วงไม่ได้เรียก pair เอง -- พวกเขาตอบสนองต่อสิ่งที่ central เริ่มต้น ว่าจะต้องการการเข้ารหัสสำหรับ characteristic ที่กำหนดนั้นเป็นคุณสมบัติของวิธีที่มันถูกประกาศในฐานข้อมูล GATT; บิตการเข้าถึงที่ต้องการการเข้ารหัสเป็นส่วนหนึ่งของ bluetooth API ระดับต่ำและปัจจุบันยังไม่ได้เปิดเผยผ่านตัวสร้าง characteristic ของ aioble
11.13.4. การผูกพัน -- และที่อยู่ของคีย์¶
เมื่อ bond=True, aioble จะเขียนคีย์ไปยังไฟล์ JSON บนระบบไฟล์ในเครื่อง ชื่อไฟล์เริ่มต้นคือ ble_secrets.json เขียนสัมพันธ์กับไดเร็กทอรีการทำงานปัจจุบัน บนกล้องที่เพิ่งบูต _boot.py ได้เลือกไดเร็กทอรีนั้นแล้ว: /sdcard เมื่อมีการ์ดติดตั้ง, /flash เมื่อไม่มี -- ดังนั้นไฟล์จะอยู่ที่ /sdcard/ble_secrets.json หรือ /flash/ble_secrets.json ไฟล์นี้เก็บรายการที่จำเป็นสำหรับการเข้ารหัสลิงก์ใหม่ในครั้งถัดไปที่เพียร์ที่ผูกพันเชื่อมต่อใหม่ รวมถึงที่อยู่ identity ของเพียร์
ความไม่สมมาตรหนึ่งที่ควรจำ: การบันทึก เกิดขึ้นโดยอัตโนมัติเมื่อคีย์เปลี่ยน แต่ การโหลด ไฟล์เมื่อบูตครั้งถัดไปไม่เกิดขึ้นเอง เรียก aioble.security.load_secrets() ครั้งหนึ่งเมื่อเริ่มต้น (ก่อนการจับคู่หรือการโฆษณาใดๆ) เพื่อให้เพียร์ที่ผูกพันก่อนหน้านี้ได้รับการรู้จัก:
import aioble
aioble.security.load_secrets() # default path: ble_secrets.json
หลังจากนั้น ครั้งถัดไปที่เพียร์ที่ผูกพันปรากฏขึ้น aioble จะนำคีย์ที่เก็บไว้มาใช้ใหม่และลิงก์จะถูกเข้ารหัสโดยไม่ต้องมีขั้นตอนการสื่อสารเพิ่มเติม
ผลที่ตามมาในทางปฏิบัติสองประการของการเก็บคีย์บนแฟลช:
การลืมอุปกรณ์ ลบ
ble_secrets.json(หรือลบรายการที่เกี่ยวข้อง) เพื่อลืมเพียร์ที่ผูกพันทั้งหมด จากนั้นจับคู่ใหม่ตั้งแต่ต้นการเข้าถึงทางกายภาพทำให้คีย์รั่วไหล ผู้ใดก็ตามที่มีสิทธิ์เข้าถึงระบบไฟล์ของกล้องสามารถอ่าน JSON ได้ นี่คือข้อจำกัดประเภทเดียวกับที่เกิดขึ้นในส่วนของระบบเครือข่ายด้วยคีย์ TLS (การดำเนินการ: คีย์ การหมดอายุ และการแก้ปัญหา): ใช้คีย์เฉพาะอุปกรณ์ ถือว่าคีย์ที่เก็บไว้ใดๆ สามารถกู้คืนได้ และอาศัยความสามารถในการเพิกถอน (ที่นี่คือการลบการผูกพันจากฝั่ง central) มากกว่าการที่คีย์ยังคงเป็นความลับ
11.13.5. สิ่งที่การเข้ารหัสรับประกัน -- และสิ่งที่ไม่รับประกัน¶
ลิงก์แบบจับคู่แล้วเข้ารหัสให้ตามลำดับความแข็งแกร่ง:
การรักษาความลับ ตลอดเวลา ผู้ดักฟังไม่สามารถอ่านไบต์ได้
ความสมบูรณ์ ตลอดเวลา แพ็กเก็ตที่ถูกแก้ไขจะล้มเหลวในการตรวจสอบ authenticated-encryption ของเลเยอร์ลิงก์และถูกทิ้ง
การพิสูจน์ตัวตน เฉพาะกับ
mitm=Trueและ IO ที่มีความสามารถ หากไม่มี man-in-the-middle ที่ดักจับการแลกเปลี่ยนการจับคู่ ครั้งแรก อาจแทรกตัวเองเข้ามาได้; หากไม่มีการป้องกัน MITM ทั้งสองฝ่ายไม่มีทางรู้ได้
สำหรับกรณีการใช้กล้องส่วนใหญ่ -- โทรศัพท์จับคู่กับกล้องครั้งหนึ่ง แล้วเชื่อมต่อใหม่ในภายหลัง -- mitm=False มักเพียงพอ เพราะการจับคู่ครั้งแรกเกิดขึ้นในสภาพแวดล้อมที่ควบคุม (ผู้ใช้ถืออุปกรณ์ทั้งสองในห้องเดียวกัน) สำหรับแอปพลิเคชันที่อุปกรณ์ที่จับคู่อาจพบกล้องครั้งแรกในระยะไกลหรือผ่านตัวกลางที่ไม่น่าเชื่อถือ MITM คือการตั้งค่าที่ถูกต้อง
11.13.6. เมื่อการจับคู่เป็นคำตอบที่ไม่ถูกต้อง¶
การจับคู่มีต้นทุนจริง: การแลกเปลี่ยนสักไม่กี่วินาทีเมื่อเชื่อมต่อครั้งแรก การใช้แฟลชถาวรสำหรับทุกอุปกรณ์ที่ผูกพัน และเรื่องการกู้คืนของ "ลืมการผูกพัน" หากมีสิ่งผิดพลาด สำหรับข้อมูลสาธารณะจริงๆ -- การอ่านค่า sensor แวดล้อมที่เผยแพร่เป็น beacon ป้ายที่แสดงชื่อ สิ่งใดก็ตามที่ไม่เปลี่ยนแปลงโลกด้วยการอ่านหรือเขียน -- คำตอบที่ถูกต้องคือ ไม่ เข้ารหัสเลย และปล่อยให้เครื่องสแกนใกล้เคียงอ่านค่าได้
สำหรับสิ่งอื่นๆ ทั้งหมด connection.pair(bond=True) บน central คือการเพิ่มหนึ่งบรรทัดที่เปลี่ยนลิงก์จากช่องสาธารณะเป็นช่องส่วนตัว