ภาพพื้นหลังปกบทเรียน

บทเรียน 4.7 — TLS: ใบรับรอง ห่วงโซ่ความเชื่อถือ และการจับมือ

จากพอร์ต 1883 ที่ใครก็อ่านได้ ไปพอร์ต 8884 ที่รู้ว่ากำลังคุยกับใคร

โมดูล 4 — เชื่อมต่อแพลตฟอร์ม IoT

คาถาประจำบทเรียน: เราไม่ได้เข้ารหัสเพราะมันดูเป็นมืออาชีพ — เราเข้ารหัสเพราะถ้าไม่เข้ารหัส ทุกคนในเครือข่ายเดียวกันคืออุปกรณ์ของเรา

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ดูของจริงก่อน — รหัสผ่านของเราบนหน้าจอคนอื่น

บทเรียน 4.4–4.6 · พอร์ต 1883 — สิ่งที่คนดักฟังเห็น MQTT CONNECT username: team03 password: Kx7pQm2wLz9vRt4B {"accel_x":0.12,"pot":48.2} อ่านได้ทุกไบต์ ไม่ต้องถอดรหัสอะไรเลย วันนี้ · พอร์ต 8884 — สิ่งที่คนดักฟังเห็น TLS Application Data 17 03 03 00 4a 9c e1 b0 ... 3f a7 20 dd 61 8e 4c 05 ... ยาวเท่าเดิม เวลาเดิม แต่เนื้อในหายไป เห็นชื่อโฮสต์ปลายทางได้อย่างเดียว ความลับรั่วออกไปเรื่อย ๆ รั่วได้แค่ "มีคนคุยกัน" ไม่ใช่ "คุยว่าอะไร"

บอร์ดตัวเดียวกัน เครือข่ายเดียวกัน โค้ดเกือบเหมือนเดิมทุกบรรทัด — สิ่งที่เปลี่ยนคือเราเรียกโมดูลไหน และผลของมันเห็นได้ด้วยตาบนเครื่องมือดักจับ

ชุดบทเรียนก่อนหน้าเราทำให้ ส่งได้ วันนี้เราจะทำให้ คนอื่นแอบฟังไม่ได้ และรู้ด้วยว่ากำลังส่งให้ใคร

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ทำไม · คืออะไร · ทำยังไง — แผนที่ของชุดบทเรียนนี้

คำถาม คำตอบของชุดบทเรียนนี้ อยู่ช่วงไหน
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 เราทำให้ ส่งได้ · ชุดบทเรียนนี้เราทำให้คนอื่นแอบฟังไม่ได้ และรู้ด้วยว่ากำลังส่งให้ใคร

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เป้าหมายของชุดบทเรียนนี้

  1. อธิบายได้ว่า serverTLS ปกป้องอะไร (ช่องทาง + ตัวตนของเซิร์ฟเวอร์) และ ไม่ปกป้องอะไร (ตัวตนของอุปกรณ์)
  2. อ่านลำดับการจับมือ TLS ได้ระดับวิศวกรทำงาน — ใบรับรอง, CA, ห่วงโซ่ความเชื่อถือ, SNI
  3. ใช้ tesaiot.config_set() / connect() / is_connected() / publish() ได้ถูกต้องตามข้อจำกัดจริงของเฟิร์มแวร์
  4. เทียบสิ่งที่คนดักจับสัญญาณเห็นระหว่างพอร์ต 1883 กับ 8884 แล้วสรุปเป็นตารางของทีมเอง

ปลายทางของวันนี้: กราฟของ device_id ทีมเราขยับอยู่บน dashboard ของแพลตฟอร์ม โดยข้อมูลเดินผ่านช่องที่เข้ารหัสตลอดทาง

ชุดบทเรียนนี้โค้ดสั้นที่สุดในตอนที่ 4 แต่เป็นบทเรียนที่ ความเข้าใจผิดแพงที่สุด

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ปลายทางของชุดบทเรียนนี้ — ข้อความเดิม แต่เดินในท่อที่เข้ารหัสแล้ว

หน้าจอจาก BENTO Emulator ของ 06_secure_publish_loop.py ที่ส่งข้อความผ่าน MQTTs

หน้าจอจากการรัน 06_secure_publish_loop.py บน BENTO Emulator ที่ 800x480 เท่าจอของทั้งสองบอร์ด — ไม่ใช่ภาพวาด ไม่ใช่ mock-up และไม่ใช่ภาพถ่ายจากบอร์ด · หน้าจอของไฟล์เฉลย (ตารางตัวตน · ไฟสามดวงของการจับมือ · ปุ่มต่อใหม่/ตัดสาย · มาตรวัดเวลาจับมือ) ยังไม่ได้ถ่าย
  • การ์ดบนบอกโหมดกับพอร์ตที่ใช้จริง serverTLS -> 8884 · เลขใหญ่นับใบที่ส่งสำเร็จ · "สาย: ต่ออยู่" จะเปลี่ยนเป็นแดงทันทีที่หลุด
  • กราฟล่างคือจังหวะการส่ง (ms ระหว่างสองครั้ง) — เส้นราบแปลว่าลูปเดินสม่ำเสมอ ไม่มีรอบไหนค้าง
  • บรรทัดล่างสุดคือหลักฐานของชุดบทเรียน: TLS สำเร็จใน 2703 ms — การจับมือนับเป็นวินาที และต้องเช็ก is_connected() ก่อนส่งทุกครั้ง

หน้าตาแทบไม่ต่างจากบทเรียน 4.4–4.6 — สิ่งที่เปลี่ยนคือเลขพอร์ต กับบรรทัด "TLS สำเร็จ" ที่ต้องรอเป็นวินาทีกว่าจะขึ้น

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ทบทวนบทเรียน 4.4–4.6 — เราหยุดไว้ตรงไหน

mqtt.connect() ต่อ broker ได้ publish() ส่ง JSON ทุก 5 วิ subscribe() รับคำสั่งกลับมา TESAIoT CE ที่ติดตั้งเอง วันนี้ tesaiot.* พอร์ต 8884 บทเรียน 4.4–4.6 ข้อมูลไหลครบสองทางแล้ว — แต่ไหลแบบเปลือย ต้องหยิบมาใช้ต่อวันนี้: JSON ส่งแบน ไม่ต้องห่อ · device_id ไม่เกิน 31 ตัวอักษร · ค่าต้องเป็นตัวเลขถึงขึ้นกราฟ สิ่งที่ยังไม่ได้ทำ: พิสูจน์ว่าปลายทางเป็นตัวจริง และปิดไม่ให้คนกลางอ่าน

โมดูลก็เปลี่ยนด้วย — บทเรียน 4.4–4.6 ใช้ mqtt.* ที่เราเลือกโฮสต์และพอร์ตเองได้ ส่วนวันนี้ใช้ tesaiot.* ซึ่งเป็นโมดูลคนละตัว ตั้งค่าคนละแบบ และ เลือกพอร์ตเองไม่ได้

ทุกข้อจำกัดของ mqtt ในชุดบทเรียนก่อนหน้ายังอยู่ครบ วันนี้แค่เพิ่มชั้นความปลอดภัยทับลงไป ไม่ได้ลบข้อจำกัดเดิม

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ก่อนเริ่มบทเรียน — บอร์ดทุกตัวต้องมีตัวตนของตัวเอง

หน้าจอรายการอุปกรณ์ของ TESAIoT Community Edition ที่ใช้ลงทะเบียนตัวตนของอุปกรณ์ การ์ด Hardware Security Module รุ่น nCipher nShield ที่เก็บกุญแจเข้ารหัสไว้ในฮาร์ดแวร์

ซ้าย — ภาพหน้าจอ: TESAIoT Community Edition v1.1.8 — เอกสารของ repo (Apache-2.0) · ขวา — ภาพ: Alexander Klink / Wikimedia Commons — CC BY 3.0 — การ์ด HSM (nCipher nShield) ตัวจริงที่เสียบอยู่ในเครื่องของ CA: ตัวตนที่อุปกรณ์กำลังจะได้รับ ถูกเซ็นด้วยกุญแจที่อยู่ในของแบบนี้ ไม่ใช่ไฟล์บนโน้ตบุ๊กของใคร

บอร์ดทุกตัวออกจากโรงงานมาพร้อม device_id ค่าเริ่มต้นตัวเดียวกันหมด และ MQTT บังคับว่า client id ต้องไม่ซ้ำกันบน broker เดียวกัน

พอบอร์ดตัวที่สองต่อเข้ามาด้วย id เดิม broker จะ เตะตัวแรกออก ตัวแรกต่อใหม่แล้วเตะตัวที่สองออก วนแบบนี้ไปเรื่อย ๆ โดยที่โค้ดของทุกบอร์ด ถูกต้องหมด

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

id ซ้ำ = ลูปเตะกันเอง บอร์ด A บอร์ด B broker

ถ้ายังไม่ได้ค่าครบสี่ตัว อย่าเพิ่งเริ่มท่าที่ 2 — บอร์ดจะต่อด้วยตัวตนค่าเริ่มต้นที่ซ้ำกับบอร์ดตัวอื่น แล้วเตะกันหลุดบน broker

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

กุญแจ ลายเซ็น และแฮช — สามชิ้นที่ TLS ประกอบขึ้นมา

แผนภาพการเข้ารหัสด้วยกุญแจสาธารณะ และถอดรหัสด้วยกุญแจส่วนตัว แผนภาพลายเซ็นดิจิทัล: เซ็นด้วยกุญแจส่วนตัว ตรวจด้วยกุญแจสาธารณะ แผนภาพฟังก์ชันแฮช ข้อความต่างกันได้ค่าแฮชต่างกันอย่างสิ้นเชิง

ซ้าย/กลาง — ภาพ: Davidgothberg / Wikimedia Commons — สาธารณสมบัติ · ขวา — ภาพ: Jorge Stolfi (ต่อยอดจากงานของ Helix84) / Wikimedia Commons — สาธารณสมบัติ

ซ้าย — กุญแจคู่ ล็อกด้วยกุญแจสาธารณะของ Alice แล้ว มีแต่กุญแจส่วนตัวของ Alice ที่เปิดได้ จึงส่งความลับให้คนที่ไม่เคยเจอกันได้ โดยไม่ต้องนัดรหัสกันก่อน

กลาง — ลายเซ็น คือการกลับทิศ เซ็นด้วยกุญแจส่วนตัว ใครก็ตรวจได้ด้วยกุญแจสาธารณะ — พิสูจน์ว่า "คนที่ถือกุญแจส่วนตัวใบนี้เป็นผู้เขียน" นี่คือกลไกที่ CA ใช้รับรองใบรับรอง

ขวา — แฮช ข้อความเปลี่ยนแค่ตัวอักษรเดียว ค่าที่ได้เปลี่ยนทั้งก้อน จึงใช้ย่อเอกสารยาว ๆ ให้เหลือค่าเดียวก่อนเซ็น และใช้ตรวจว่าข้อมูลระหว่างทางถูกแก้หรือไม่

จำสามคำนี้ให้แม่น: เข้ารหัส = ปิดไม่ให้อ่าน · เซ็น = พิสูจน์ว่าใครเขียน · แฮช = จับได้ว่าถูกแก้ TLS ใช้ทั้งสามพร้อมกันเสมอ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ใบรับรองคืออะไรกันแน่ — เปิดดูข้างในทีละช่อง

ใบรับรอง X.509 ของเซิร์ฟเวอร์ Subject — ชื่อที่ใบนี้พูดถึง CN = broker.tesaiot.dev Public Key — กุญแจสาธารณะของเซิร์ฟเวอร์ RSA 2048 หรือ EC P-256 Validity — ช่วงเวลาที่ใช้ได้ notBefore / notAfter Issuer + Signature — ใครรับรอง และลายเซ็น CN = TESAIoT Intermediate CA ลายเซ็นนี้คือทั้งหมดที่ทำให้เชื่อได้ ใบรับรองรับรองอะไร "กุญแจสาธารณะใบนี้ เป็นของชื่อโฮสต์นี้จริง" และมี CA ที่เรารู้จักเซ็นรับรองข้อความนั้นไว้ ใบรับรองเป็นข้อมูลสาธารณะ ไม่ใช่ความลับ ก๊อปได้ ใบรับรอง ไม่ ได้รับรองอะไร ไม่ได้บอกว่าเจ้าของเป็นคนดีหรือปลอดภัย ไม่ได้บอกว่าข้อมูลที่ส่งไปจะถูกเก็บอย่างดี พิสูจน์แค่ "ชื่อคู่กับกุญแจ" — เท่านั้นจริง ๆ

หน้าต่างรายละเอียดใบรับรองดิจิทัลในเบราว์เซอร์ แสดงช่อง Issuer Validity และ Subject

ภาพ: Winstonlee / Wikimedia Commons — CC BY-SA 4.0 — ใบรับรองจริงที่เปิดดูจากเบราว์เซอร์บนเครื่องผู้ใช้: ช่อง Issuer, Validity และ Subject ที่กล่องซ้ายมือกำลังไล่อธิบาย อยู่ครบในหน้าต่างนี้ และกรอบบนสุดคือห่วงโซ่ root → intermediate → leaf ของสไลด์ถัดไป

สิ่งที่ทำให้ใบรับรองมีค่าไม่ใช่เนื้อหาข้างใน (ใครก็พิมพ์ได้) แต่คือ ลายเซ็นของ CA ที่อยู่ท้ายใบ — และเราตรวจลายเซ็นนั้นได้ก็ต่อเมื่อ มีกุญแจสาธารณะของ CA อยู่ในมือแล้วตั้งแต่ต้น

ประโยคที่ควรจำไปใช้ทำงาน: ใบรับรองแปลว่า "มีคนที่คุณเชื่ออยู่แล้ว ยืนยันว่ากุญแจนี้เป็นของชื่อนี้" ไม่มากกว่านั้นแม้แต่นิดเดียว

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ห่วงโซ่ความเชื่อถือ — root → intermediate → leaf

แผนภาพห่วงโซ่ความเชื่อถือของใบรับรอง จาก root ผ่าน intermediate ถึงใบรับรองปลายทาง

ภาพ: Yuhkih / Wikimedia Commons — CC BY-SA 4.0

แผนภาพอุปกรณ์ตรวจ TLS ที่ถอดและเข้ารหัสใหม่ระหว่างผู้ใช้กับเซิร์ฟเวอร์

ภาพ: Rudolf.Achter / Wikimedia Commons — CC BY-SA 4.0

ซ้าย — ใบของเซิร์ฟเวอร์ (leaf) ถูกเซ็นโดย intermediate, intermediate ถูกเซ็นโดย root และ root เซ็นตัวเอง ห่วงโซ่จบตรงนั้นเสมอ เพราะ root คือสิ่งที่เรา "ตัดสินใจเชื่อ" ไว้ล่วงหน้า ไม่ใช่สิ่งที่พิสูจน์ได้ · ขวา — ถ้ามีกล่องกลางทางที่เรา (หรือผู้ดูแลเครือข่าย) ใส่ CA ของมันไว้ในเครื่อง มันจะออกใบรับรองชื่อเดียวกันได้ และเราจะเชื่อโดยไม่รู้ตัว — นั่นคือเหตุผลว่าทำไม รายชื่อ CA ที่เชื่อ ถึงสำคัญพอ ๆ กับตัวการเข้ารหัส

PKI Bootcamp — Basics of Certificate Chain Validation — Paul Turner · 3 นาที 42 วินาที · อังกฤษ — ตอบคำถาม "ทำไมบอร์ดต้องมี root CA ติดตัว" ได้ครบใน 4 นาที

ความเชื่อไม่ได้เกิดจากการพิสูจน์ทั้งเส้น มันเกิดจาก จุดเริ่มต้นที่เราเลือกเชื่อไว้ก่อน แล้วพิสูจน์ต่อจากจุดนั้นลงมา

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

การจับมือ TLS ทีละขั้น — ในภาษาที่เราใช้กันจริง

แผนภาพการจับมือ TLS 1.2 ทีละขั้นระหว่างบอร์ดกับ broker พร้อมคำอธิบายภาษาไทย

พื้นฐาน 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

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เกร็ด: TLS 1.3 ตัดรอบไป-กลับออกไปหนึ่งรอบ

แผนภาพลำดับการจับมือ TLS 1.2 แบบเต็มระหว่าง client กับ server แผนภาพลำดับการจับมือ TLS 1.3 ที่ใช้รอบไป-กลับน้อยกว่า TLS 1.2

ภาพทั้งสอง: Fleshgrinder และ The Tango! Desktop Project / Wikimedia Commons — สาธารณสมบัติ · ซ้าย TLS 1.2 · ขวา TLS 1.3

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 ทันที

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

SNI — ชื่อที่เดินไปก่อนการเข้ารหัส

บอร์ดของเรา ClientHello ยังไม่เข้ารหัส เครื่องเดียว หนึ่ง IP หลายชื่อโฮสต์ ใบรับรอง A ใบรับรอง B server_name = sni_hostname ตั้งตรงกับ broker ได้ใบที่ถูก ตรวจผ่าน ต่อติด ตั้งไม่ตรง ได้ใบผิด ตรวจไม่ผ่าน ล้มเงียบ SNI คือชื่อโฮสต์ที่เดินไปแบบเปิดเผย ก่อนการเข้ารหัสจะเริ่ม นี่คือสิ่งเดียวที่คนดักฟังยังเห็นได้บนพอร์ต 8884 — เห็นว่าเราคุยกับใคร แต่ไม่เห็นว่าคุยว่าอะไร

เซิร์ฟเวอร์ตัวเดียวโฮสต์หลายชื่อได้ จึงต้องรู้ตั้งแต่ประโยคแรกว่าเราจะคุยกับชื่อไหน ถึงจะหยิบใบรับรองใบที่ถูกมายื่นให้ — นี่คือหน้าที่ของ sni_hostname ในโค้ดวันนี้ และเป็นเหตุผลที่มันต้อง เท่ากับชื่อ broker เป๊ะ ๆ

ตั้ง sni_hostname ผิด อาการที่ได้คือ "ต่อไม่ติด โดยไม่มีข้อความอะไรเลย" — ไม่ใช่ error ที่บอกว่าชื่อผิด จำอาการนี้ไว้ตั้งแต่ตอนนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เข้าใจฮาร์ดแวร์ · TLS วิ่งอยู่ตรงไหนบนบอร์ด

CM33_NS — คอร์ที่รัน MicroPython โค้ด Python ของเรา tesaiot.publish() งาน TLS + MQTT เข้ารหัสทุกไบต์ที่ออก ไดรเวอร์ WiFi — วิทยุตัวเดียวของทั้งบอร์ด root CA ถูกฝังไว้ในเฟิร์มแวร์ตั้งแต่ตอน build CM55 — คอร์ที่วาดจอและอ่านเซนเซอร์ อ่าน CapSense / pot ให้เรา · IMU ด้วยบน Eva วาดผลบนจอผ่าน LVGL ไม่แตะเครือข่ายและไม่แตะการเข้ารหัสเลย ค่าเซนเซอร์เดินข้ามมาทาง IPC ก่อนถูกเข้ารหัส จอค้างไม่ได้แปลว่า TLS หลุด และในทางกลับกันด้วย TLS ต้องการหน่วยความจำก้อนใหญ่ที่สุดตอนจับมือ — ไม่ใช่ตอนส่งข้อมูล นี่คือเหตุผลที่เฟิร์มแวร์จัดสรรหน่วยความจำให้เส้นทาง tesaiot ไว้ล่วงหน้า และเป็นเหตุผลที่ MPY heap มีแค่ 64 KB

การเข้ารหัสทั้งหมดเกิดบน CM33_NS คอร์เดียวกับที่รันโค้ด Python ทุกไบต์ที่ tesaiot.publish() ส่งออกไปจะถูกเข้ารหัสก่อนลงสายอากาศ ส่วน CM55 ที่วาดจอไม่รู้เรื่องด้วยเลย — ภาพนี้จริงทั้งสองบอร์ด เพราะโค้ด Wi-Fi/MQTT/TLS เป็นชุดเดียวกัน ต่างกันแค่ว่าใครอ่าน IMU: บน Eva คอร์จออ่านให้ บน Dev Kit CM33 อ่านเองจาก I2C (CapSense กับลูกบิดยังมาจากคอร์จอทั้งคู่)

ข้อที่ต้องจำ: ช่วงจับมือคือช่วงที่กินหน่วยความจำและเวลามากที่สุด ถ้าสคริปต์ของเราสร้าง widget เพียบหรือเก็บลิสต์ใหญ่ ๆ ไว้ก่อนเรียก connect() โอกาสล้มจะสูงขึ้นทันที — ต่อให้เน็ตดีทุกอย่าง

เรียก tesaiot.connect() ตอนต้นสคริปต์ ตอนหน่วยความจำยังโล่ง แล้วค่อยไปทำอย่างอื่น อย่าเรียกกลางลูปที่ของเต็มมือ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

กลไกหลักของชุดบทเรียน — พอร์ตมาจาก tls_mode ไม่ใช่คีย์ port

กับดักข้อแรกของชุดบทเรียน: มีคีย์ชื่อ port อยู่จริง แต่มันไม่ได้เลือกพอร์ต config_set("tls_mode", "server_tls") ค่าเริ่มต้นของบอร์ดอยู่แล้ว config_set("port", 1883) ตั้งได้ ไม่ error แต่เปลี่ยนแค่ป้ายที่แสดง เฟิร์มแวร์ อ่าน tls_mode แล้วเลือกพอร์ตเอง ตัน server_tls → 8884 เส้นทางของชุดบทเรียนนี้ mutual_tls → 8883 เส้นทางที่ต้องมีใบรับรองของอุปกรณ์ จอ Eva แสดงเลขที่เราตั้ง ค่าที่แสดง ≠ ค่าที่ระบบใช้จริง พอร์ตเป็นผลลัพธ์ ไม่ใช่ค่าที่รับเข้ามา

นี่คือรูปแบบที่จะเจอไปทั้งชีวิตการทำงาน: ค่าที่ตั้งได้ ไม่ได้แปลว่าค่านั้นมีผล และ ค่าที่จอแสดง ไม่ได้แปลว่าระบบใช้ค่านั้น ในบันทึกการเรียน ผู้เรียนจะได้ลองตั้ง port ให้ผิดแล้วดูเองว่าพอร์ตจริงไม่ขยับ · "จอ" ในกล่องล่างขวาคือการ์ด TESAIoT Connectivity ซึ่งมีบนหน้า Home ของ Eva Kit เท่านั้น — บน Dev Kit ไม่มีการ์ดนี้ ให้ดูจาก print(tesaiot.config()) แทน ผลเหมือนกันทุกประการ: คีย์ port เปลี่ยน แต่พอร์ตที่ต่อจริงไม่เปลี่ยน

ถ้าอยากรู้ว่าระบบใช้พอร์ตอะไรจริง ๆ ให้ดู tls_mode — และถ้าอยากรู้ว่า API ตัวไหนหลอกเรา ให้ วัดผลที่ปลายทาง ไม่ใช่อ่านค่าที่ตัวเองเพิ่งตั้ง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ทำไม MQTTs ยิงเข้า CE ที่ติดตั้งเองไม่ได้

บอร์ดของเรา root CA ของแพลตฟอร์ม คอมไพล์ติดมากับเฟิร์มแวร์ ไม่มี API ให้เปลี่ยนตอนรัน เปลี่ยนได้ทางเดียวคือ build ใหม่ แพลตฟอร์ม TESAIoT ใบรับรองห้อยจาก root ใบนั้น ตรวจผ่าน · ต่อได้จริง นี่คือปลายทางของบทเรียน 4.7–4.9 TESAIoT CE ที่ติดตั้งเอง สุ่ม root CA ใหม่ทุกครั้งที่ติดตั้ง บอร์ดไม่รู้จัก จึงตรวจไม่ผ่าน ไม่ใช่บั๊ก — เป็นผลของการออกแบบ 8884 · ผ่าน 8884 · ไม่ผ่าน บทเรียน 4.4–4.6 ใช้ 1883 กับ CE จึงทำได้

บทเรียน 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 ที่ได้มาพร้อมตัวตนของอุปกรณ์

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

serverTLS พิสูจน์ตัวตนได้ข้างเดียว

แผนภาพการจับมือ TLS แบบสองทาง ทั้งสองฝั่งยื่นใบรับรองให้กัน (mTLS)

ภาพ: Essich / Wikimedia Commons — CC BY 3.0 — ภาพนี้คือ mTLS ที่ยื่นใบรับรอง ทั้งสองฝั่ง วันนี้เราทำแค่ครึ่งเดียวของมัน

สิ่งที่วันนี้ทำได้จริง

  • ข้อมูลถูกเข้ารหัสตลอดทาง คนกลางอ่านไม่ได้ และแก้ระหว่างทางไม่ได้โดยเราไม่รู้
  • เรารู้ว่า เซิร์ฟเวอร์เป็นตัวจริง เพราะมันยื่นใบที่ CA ของเราเซ็น และชื่อในใบตรงกับ SNI ที่เราขอ

สิ่งที่วันนี้ยัง ไม่ ได้ทำ

  • เซิร์ฟเวอร์ ไม่รู้ว่าอุปกรณ์ตัวไหนพูด — มันรู้แค่ว่ามีคนที่รู้ device_id กับ mqtt_pass ที่ถูกต้อง
  • ความลับชนิดนั้น คัดลอกได้ ใครได้รหัสไปก็ปลอมเป็นบอร์ดเราได้ทันที และเซิร์ฟเวอร์แยกไม่ออก
  • ในภาพซ้าย ขั้น "client certificate" คือส่วนที่หายไป — นั่นคือ mTLS ที่ต้องมีกุญแจส่วนตัวอยู่ในอุปกรณ์จริง ๆ

ประโยคที่ต้องตอบได้โดยไม่เปิดสไลด์: serverTLS พิสูจน์ช่องทางและพิสูจน์เซิร์ฟเวอร์ — ไม่ได้พิสูจน์อุปกรณ์ ตัวตนอุปกรณ์วันนี้มาจากรหัสผ่าน ซึ่งเป็นความลับที่ถูกก๊อปได้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

1883 กับ 8884 — ตารางที่ทีมต้องกรอกให้ได้เอง

แผนภาพ broker ตัวเดียวที่เปิดทั้งช่องทางธรรมดาและช่องทาง TLS ที่มีใบรับรอง

ภาพ: Ademant / Wikimedia Commons — CC BY-SA 4.0 — broker ตัวเดียวเปิดได้ทั้ง listener ธรรมดาและ listener ที่มีใบรับรอง
บทเรียน 4.4–4.6 · 1883 วันนี้ · 8884
การเข้ารหัส ไม่มีเลย TLS 1.2
ตัวตนของ broker ไม่มีการพิสูจน์ ใบรับรองที่ CA เซ็น + ตรวจ SNI
ตัวตนของอุปกรณ์ client_id ที่ใครก็อ้างได้ credentials ที่ provision รายอุปกรณ์
ปลายทาง CE ที่ติดตั้งเอง แพลตฟอร์ม TESAIoT
โมดูล mqtt tesaiot

พอร์ต 1883 ไม่ได้ "ปลอดภัยน้อยกว่า" — มันไม่มีความปลอดภัยเลย ทั้งเรื่องเนื้อหาและเรื่องตัวตน สิ่งที่ 8884 เพิ่มเข้ามาคือสองอย่างพร้อมกัน: การเข้ารหัส และการรู้ว่ากำลังคุยกับใคร

อย่าท่องตารางนี้ — ให้ ดักจับเอง แล้วกรอกในบันทึกการเรียนจากสิ่งที่เห็นด้วยตา นั่นคือหลักฐานที่ใช้ได้จริง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0