| คำถาม | คำตอบของชุดบทเรียนนี้ | อยู่ช่วงไหน | |
|---|---|---|---|
| Why | บทเรียน 4.4–4.6 ส่งขึ้น broker ได้แล้ว ทำไมต้องย้ายพอร์ตอีก | เพราะพอร์ต 1883 ไม่ได้ "ปลอดภัยน้อยกว่า" — มันไม่มีความปลอดภัยเลย รหัสผ่านของทีมเดินเป็นข้อความเปล่าให้ทุกคนในเครือข่ายเดียวกันอ่านได้ · และชุดบทเรียนนี้เป็นบทเรียนแรกที่คำตอบที่ถูกที่สุดคือ "ได้ แต่แค่ระดับนี้" | ครึ่งแรก · ใบรับรอง · ห่วงโซ่ความเชื่อถือ · SNI |
| What | มีอะไรให้ใช้บ้าง | import tesaiot ได้มา 28 ชื่อ — ใช้ได้จริง เก้าตัว เหมือนกันทั้ง Eva Kit และ Dev Kit · สิบหกตัวข้ามคอร์ไปหาชิปที่เฟิร์มแวร์ของคอร์จอไม่ได้เปิดไว้ จึงได้ OSError (เวลาที่เสียไปยังไม่ได้วัดจริง) · อีกสามตัวเป็นคนละเรื่องกัน และหนึ่งในนั้น (protected_update) ห้ามเรียก เพราะบน Dev Kit มันเขียนลงชิปจริง |
สไลด์ 28 ชื่อ + ตารางเต็มของเก้าตัวที่ใช้ได้ |
| How | ประกอบยังไงให้ใช้งานได้จริง | ตั้งตัวตนด้วย config_set() → สั่ง connect() แล้ว วนรอจน is_connected() เป็นจริง เพราะฟังก์ชันคืนค่าไม่ได้แปลว่างานเสร็จ → publish() → เอาหลักฐานขึ้นจอ |
เจ็ดไฟล์ตัวอย่าง (01–06 ในบทเรียน 4.8 · 07 ในบทเรียน 4.9) + ไฟล์ฝึก |
ปลายทางที่จับต้องได้ — ข้อความชุดเดิมของบทเรียน 4.4–4.6 แต่เดินในท่อที่เข้ารหัส กราฟของ device_id ทีมเราขยับอยู่บน dashboard ของแพลตฟอร์ม และ Console ยืนยันว่าโหมดคือ server_tls -> 8884
บทเรียน 4.4–4.6 เราทำให้ ส่งได้ · ชุดบทเรียนนี้เราทำให้คนอื่นแอบฟังไม่ได้ และรู้ด้วยว่ากำลังส่งให้ใคร
tesaiot.config_set() / connect() / is_connected() / publish() ได้ถูกต้องตามข้อจำกัดจริงของเฟิร์มแวร์ปลายทางของวันนี้: กราฟของ device_id ทีมเราขยับอยู่บน dashboard ของแพลตฟอร์ม โดยข้อมูลเดินผ่านช่องที่เข้ารหัสตลอดทาง
ชุดบทเรียนนี้โค้ดสั้นที่สุดในตอนที่ 4 แต่เป็นบทเรียนที่ ความเข้าใจผิดแพงที่สุด

06_secure_publish_loop.py บน BENTO Emulator ที่ 800x480 เท่าจอของทั้งสองบอร์ด — ไม่ใช่ภาพวาด ไม่ใช่ mock-up และไม่ใช่ภาพถ่ายจากบอร์ด · หน้าจอของไฟล์เฉลย (ตารางตัวตน · ไฟสามดวงของการจับมือ · ปุ่มต่อใหม่/ตัดสาย · มาตรวัดเวลาจับมือ) ยังไม่ได้ถ่ายis_connected() ก่อนส่งทุกครั้งหน้าตาแทบไม่ต่างจากบทเรียน 4.4–4.6 — สิ่งที่เปลี่ยนคือเลขพอร์ต กับบรรทัด "TLS สำเร็จ" ที่ต้องรอเป็นวินาทีกว่าจะขึ้น
โมดูลก็เปลี่ยนด้วย — บทเรียน 4.4–4.6 ใช้ mqtt.* ที่เราเลือกโฮสต์และพอร์ตเองได้ ส่วนวันนี้ใช้ tesaiot.* ซึ่งเป็นโมดูลคนละตัว ตั้งค่าคนละแบบ และ เลือกพอร์ตเองไม่ได้
ทุกข้อจำกัดของ
mqttในชุดบทเรียนก่อนหน้ายังอยู่ครบ วันนี้แค่เพิ่มชั้นความปลอดภัยทับลงไป ไม่ได้ลบข้อจำกัดเดิม

บอร์ดทุกตัวออกจากโรงงานมาพร้อม device_id ค่าเริ่มต้นตัวเดียวกันหมด และ MQTT บังคับว่า client id ต้องไม่ซ้ำกันบน broker เดียวกัน
พอบอร์ดตัวที่สองต่อเข้ามาด้วย id เดิม broker จะ เตะตัวแรกออก ตัวแรกต่อใหม่แล้วเตะตัวที่สองออก วนแบบนี้ไปเรื่อย ๆ โดยที่โค้ดของทุกบอร์ด ถูกต้องหมด
ตัวตนต้อง provision แยกรายอุปกรณ์ และต้องได้ครบสี่ค่า: device_id · api_key · mqtt_pass · ชื่อโฮสต์ของ broker — เพิ่มอุปกรณ์ในบัญชี TESAIoT Platform ของคุณ แล้วจดสี่ค่าจากหน้าจัดการอุปกรณ์ของแพลตฟอร์มลงบันทึกการเรียนก่อนแตะโค้ด (CE ที่ติดตั้งเองใช้กับ MQTTs ของชุดนี้ไม่ได้ ดูสไลด์เรื่อง root CA · ถ้าเรียนเป็นกลุ่ม ผู้จัดอาจเตรียมตัวตนไว้ให้)
ถ้ายังไม่ได้ค่าครบสี่ตัว อย่าเพิ่งเริ่มท่าที่ 2 — บอร์ดจะต่อด้วยตัวตนค่าเริ่มต้นที่ซ้ำกับบอร์ดตัวอื่น แล้วเตะกันหลุดบน broker
ซ้าย — กุญแจคู่ ล็อกด้วยกุญแจสาธารณะของ Alice แล้ว มีแต่กุญแจส่วนตัวของ Alice ที่เปิดได้ จึงส่งความลับให้คนที่ไม่เคยเจอกันได้ โดยไม่ต้องนัดรหัสกันก่อน
กลาง — ลายเซ็น คือการกลับทิศ เซ็นด้วยกุญแจส่วนตัว ใครก็ตรวจได้ด้วยกุญแจสาธารณะ — พิสูจน์ว่า "คนที่ถือกุญแจส่วนตัวใบนี้เป็นผู้เขียน" นี่คือกลไกที่ CA ใช้รับรองใบรับรอง
ขวา — แฮช ข้อความเปลี่ยนแค่ตัวอักษรเดียว ค่าที่ได้เปลี่ยนทั้งก้อน จึงใช้ย่อเอกสารยาว ๆ ให้เหลือค่าเดียวก่อนเซ็น และใช้ตรวจว่าข้อมูลระหว่างทางถูกแก้หรือไม่
จำสามคำนี้ให้แม่น: เข้ารหัส = ปิดไม่ให้อ่าน · เซ็น = พิสูจน์ว่าใครเขียน · แฮช = จับได้ว่าถูกแก้ TLS ใช้ทั้งสามพร้อมกันเสมอ

สิ่งที่ทำให้ใบรับรองมีค่าไม่ใช่เนื้อหาข้างใน (ใครก็พิมพ์ได้) แต่คือ ลายเซ็นของ CA ที่อยู่ท้ายใบ — และเราตรวจลายเซ็นนั้นได้ก็ต่อเมื่อ มีกุญแจสาธารณะของ CA อยู่ในมือแล้วตั้งแต่ต้น
ประโยคที่ควรจำไปใช้ทำงาน: ใบรับรองแปลว่า "มีคนที่คุณเชื่ออยู่แล้ว ยืนยันว่ากุญแจนี้เป็นของชื่อนี้" ไม่มากกว่านั้นแม้แต่นิดเดียว
ซ้าย — ใบของเซิร์ฟเวอร์ (leaf) ถูกเซ็นโดย intermediate, intermediate ถูกเซ็นโดย root และ root เซ็นตัวเอง ห่วงโซ่จบตรงนั้นเสมอ เพราะ root คือสิ่งที่เรา "ตัดสินใจเชื่อ" ไว้ล่วงหน้า ไม่ใช่สิ่งที่พิสูจน์ได้ · ขวา — ถ้ามีกล่องกลางทางที่เรา (หรือผู้ดูแลเครือข่าย) ใส่ CA ของมันไว้ในเครื่อง มันจะออกใบรับรองชื่อเดียวกันได้ และเราจะเชื่อโดยไม่รู้ตัว — นั่นคือเหตุผลว่าทำไม รายชื่อ CA ที่เชื่อ ถึงสำคัญพอ ๆ กับตัวการเข้ารหัส
PKI Bootcamp — Basics of Certificate Chain Validation — Paul Turner · 3 นาที 42 วินาที · อังกฤษ — ตอบคำถาม "ทำไมบอร์ดต้องมี root CA ติดตัว" ได้ครบใน 4 นาที
ความเชื่อไม่ได้เกิดจากการพิสูจน์ทั้งเส้น มันเกิดจาก จุดเริ่มต้นที่เราเลือกเชื่อไว้ก่อน แล้วพิสูจน์ต่อจากจุดนั้นลงมา
พื้นฐาน SSL TLS HTTPS CSR Certificate — SaKKo sama · 11 นาที 56 วินาที · ไทย — คลิปภาษาไทยที่ครอบคลุมทั้ง TLS, HTTPS, CSR และใบรับรอง
สี่จังหวะที่ต้องจำ: หนึ่ง TCP ต่อวงจรก่อน (ยังไม่มีอะไรเข้ารหัส) · สอง ClientHello บอกว่าเรารองรับอะไรบ้าง และ แนบชื่อโฮสต์ปลายทางไปด้วย · สาม เซิร์ฟเวอร์ยื่นใบรับรอง เราตรวจลายเซ็นย้อนขึ้นไปถึง root ที่เรามี แล้วแลกกุญแจลับของรอบนี้ · สี่ ตั้งแต่ Finished เป็นต้นไปทุกไบต์ถูกเข้ารหัส แล้ว MQTT CONNECT ค่อยเดินเข้าไปข้างใน
ตัวเลขในภาพสมมติเวลาเดินทางเที่ยวเดียว 34 ms ตามภาพต้นฉบับ — บนเครือข่ายจริงตัวเลขเปลี่ยน แต่ จำนวนรอบไป-กลับไม่เปลี่ยน และนั่นคือเหตุผลที่ TLS ใช้เวลาเป็น "วินาที" ไม่ใช่ "มิลลิวินาที" บนอุปกรณ์เล็ก
MQTT ไม่ได้รู้เรื่อง TLS เลย — มันแค่ถูกวางไว้ ข้างใน ท่อที่ TLS สร้างเสร็จแล้ว นี่คือความหมายของตัว s ใน MQTTs
TLS 1.2 (RFC 5246, ปี 2008) ใช้ สองรอบไป-กลับ กว่าจะเริ่มส่งข้อมูลจริง ส่วน TLS 1.3 (RFC 8446, ปี 2018) ย้ายการเสนอกุญแจไปไว้ใน ClientHello เลย จึงเหลือ รอบเดียว — ในภาพคือ 136 ms เทียบกับ 68 ms และตัดชุดวิธีเข้ารหัสรุ่นเก่าที่มีปัญหาออกไปทั้งหมด
เชื่อมกับวันนี้: เฟิร์มแวร์ของเราเจรจา TLS 1.2 ไม่ใช่ 1.3 นั่นแปลว่าเวลารอเชื่อมต่อของเราอยู่ในกลุ่มบนของภาพซ้าย — ทั้ง TCP, การจับมือ, การตรวจใบรับรอง แล้วค่อยถึง MQTT CONNECT บวกกันแล้วกินเวลาหลายวินาทีบนบอร์ดที่ CPU ช้า จึงเป็นเหตุผลตรง ๆ ที่โค้ดวันนี้ ต้องมีลูปรอ ไม่ใช่เขียน publish ต่อท้าย connect ทันที
เซิร์ฟเวอร์ตัวเดียวโฮสต์หลายชื่อได้ จึงต้องรู้ตั้งแต่ประโยคแรกว่าเราจะคุยกับชื่อไหน ถึงจะหยิบใบรับรองใบที่ถูกมายื่นให้ — นี่คือหน้าที่ของ sni_hostname ในโค้ดวันนี้ และเป็นเหตุผลที่มันต้อง เท่ากับชื่อ broker เป๊ะ ๆ
ตั้ง
sni_hostnameผิด อาการที่ได้คือ "ต่อไม่ติด โดยไม่มีข้อความอะไรเลย" — ไม่ใช่ error ที่บอกว่าชื่อผิด จำอาการนี้ไว้ตั้งแต่ตอนนี้
การเข้ารหัสทั้งหมดเกิดบน CM33_NS คอร์เดียวกับที่รันโค้ด Python ทุกไบต์ที่ tesaiot.publish() ส่งออกไปจะถูกเข้ารหัสก่อนลงสายอากาศ ส่วน CM55 ที่วาดจอไม่รู้เรื่องด้วยเลย — ภาพนี้จริงทั้งสองบอร์ด เพราะโค้ด Wi-Fi/MQTT/TLS เป็นชุดเดียวกัน ต่างกันแค่ว่าใครอ่าน IMU: บน Eva คอร์จออ่านให้ บน Dev Kit CM33 อ่านเองจาก I2C (CapSense กับลูกบิดยังมาจากคอร์จอทั้งคู่)
ข้อที่ต้องจำ: ช่วงจับมือคือช่วงที่กินหน่วยความจำและเวลามากที่สุด ถ้าสคริปต์ของเราสร้าง widget เพียบหรือเก็บลิสต์ใหญ่ ๆ ไว้ก่อนเรียก connect() โอกาสล้มจะสูงขึ้นทันที — ต่อให้เน็ตดีทุกอย่าง
เรียก
tesaiot.connect()ตอนต้นสคริปต์ ตอนหน่วยความจำยังโล่ง แล้วค่อยไปทำอย่างอื่น อย่าเรียกกลางลูปที่ของเต็มมือ
tls_mode ไม่ใช่คีย์ portนี่คือรูปแบบที่จะเจอไปทั้งชีวิตการทำงาน: ค่าที่ตั้งได้ ไม่ได้แปลว่าค่านั้นมีผล และ ค่าที่จอแสดง ไม่ได้แปลว่าระบบใช้ค่านั้น ในบันทึกการเรียน ผู้เรียนจะได้ลองตั้ง port ให้ผิดแล้วดูเองว่าพอร์ตจริงไม่ขยับ · "จอ" ในกล่องล่างขวาคือการ์ด TESAIoT Connectivity ซึ่งมีบนหน้า Home ของ Eva Kit เท่านั้น — บน Dev Kit ไม่มีการ์ดนี้ ให้ดูจาก print(tesaiot.config()) แทน ผลเหมือนกันทุกประการ: คีย์ port เปลี่ยน แต่พอร์ตที่ต่อจริงไม่เปลี่ยน
ถ้าอยากรู้ว่าระบบใช้พอร์ตอะไรจริง ๆ ให้ดู
tls_mode— และถ้าอยากรู้ว่า API ตัวไหนหลอกเรา ให้ วัดผลที่ปลายทาง ไม่ใช่อ่านค่าที่ตัวเองเพิ่งตั้ง
บทเรียน 4.4–4.6 ใช้ MQTT ธรรมดา (1883) ยิงเข้า CE ที่ติดตั้งเอง — ได้จริง · บทเรียน 4.7–4.9 ใช้ MQTTs (8884) ยิงเข้าแพลตฟอร์ม TESAIoT อย่างเป็นทางการ ที่เฟิร์มแวร์ฝัง CA ไว้ตรงกัน — ได้จริง แต่ การเอา MQTTs ไปยิง CE ที่ self-host ทำไม่ได้ในวันนี้ เพราะสคริปต์ติดตั้งของ CE สร้าง root CA ใหม่แบบสุ่มทุกครั้ง ใบรับรองของ broker จึงห้อยจาก root ที่บอร์ดไม่มีทางรู้จัก
จะทำให้ได้ต้องเอา CA ของ CE ชุดนั้น ใส่กลับเข้าไปในซอร์สแล้ว build เฟิร์มแวร์ใหม่ทุกบอร์ด ต่อการติดตั้งหนึ่งชุด — เป็นงานที่ทำได้ แต่ไม่ใช่งานของชุดบทเรียนนี้
ถ้าลองแล้วต่อไม่ติด ไม่ต้องดีบักโค้ด — มันไม่ใช่โค้ดของคุณ มันคือกุญแจที่ไม่ตรงรู กลับไปใช้โฮสต์ของแพลตฟอร์ม TESAIoT ที่ได้มาพร้อมตัวตนของอุปกรณ์
สิ่งที่วันนี้ทำได้จริง
สิ่งที่วันนี้ยัง ไม่ ได้ทำ
device_id กับ mqtt_pass ที่ถูกต้องประโยคที่ต้องตอบได้โดยไม่เปิดสไลด์: serverTLS พิสูจน์ช่องทางและพิสูจน์เซิร์ฟเวอร์ — ไม่ได้พิสูจน์อุปกรณ์ ตัวตนอุปกรณ์วันนี้มาจากรหัสผ่าน ซึ่งเป็นความลับที่ถูกก๊อปได้
| บทเรียน 4.4–4.6 · 1883 | วันนี้ · 8884 | |
|---|---|---|
| การเข้ารหัส | ไม่มีเลย | TLS 1.2 |
| ตัวตนของ broker | ไม่มีการพิสูจน์ | ใบรับรองที่ CA เซ็น + ตรวจ SNI |
| ตัวตนของอุปกรณ์ | client_id ที่ใครก็อ้างได้ | credentials ที่ provision รายอุปกรณ์ |
| ปลายทาง | CE ที่ติดตั้งเอง | แพลตฟอร์ม TESAIoT |
| โมดูล | mqtt |
tesaiot |
พอร์ต 1883 ไม่ได้ "ปลอดภัยน้อยกว่า" — มันไม่มีความปลอดภัยเลย ทั้งเรื่องเนื้อหาและเรื่องตัวตน สิ่งที่ 8884 เพิ่มเข้ามาคือสองอย่างพร้อมกัน: การเข้ารหัส และการรู้ว่ากำลังคุยกับใคร
อย่าท่องตารางนี้ — ให้ ดักจับเอง แล้วกรอกในบันทึกการเรียนจากสิ่งที่เห็นด้วยตา นั่นคือหลักฐานที่ใช้ได้จริง