โมดูล 3/5 · สัปดาห์ 7–9 · 27 ชม.

C2 link ที่ปลอดภัย

UAT 367 ความมั่นคงไซเบอร์ ระบบเชื่อมโยงการบัญชาการและควบคุม และการจัดการจราจรระบบอากาศยานไร้คนขับ

เวลาเรียนประมาณ 90 นาทีร่าง รอตรวจปรับปรุงล่าสุด 27 กันยายน 2569

บทเรียน

เมื่อเรียนจบโมดูลนี้ ผู้เรียนจะสามารถ

  1. อธิบายโครงสร้างลายเซ็นของ MAVLink 2 และกฎป้องกันการส่งซ้ำ
  2. สร้างและตรวจลายเซ็นของเฟรม MAVLink 2 ด้วย SHA-256
  3. แยกการยืนยันตัวตนออกจากการเข้ารหัส และเลือกใช้ DTLS/TLS กับ AES-GCM อย่างถูกต้อง
  4. ออกแบบ C2 สองช่องทางและประเมินความพร้อมใช้งาน

ความรู้พื้นฐานที่ควรมี: UAT 367 โมดูล 1–2 · UAT 105 โมดูล 5 (HMAC)

ทำไมต้องรู้

C2 link (command and control) คือช่องทางที่ส่งคำสั่งไปยังโดรนและรับสถานะกลับ UAT 312 สอนการออกแบบลิงก์ให้สัญญาณพอและขั้นตอนเมื่อลิงก์ขาดแล้ว โมดูลนี้ตอบคำถามต่อไปว่า โดรนรู้ได้อย่างไรว่าคำสั่งมาจากผู้ควบคุมจริง ถ้าลิงก์ไม่มีการยืนยันตัวตน ใครที่มีวิทยุความถี่เดียวกันและรู้โปรโตคอลก็ส่งคำสั่งลงจอดหรือเปลี่ยนเส้นทางได้ ในการทำ threat model ของโมดูล 1 ภัยนี้ได้คะแนน 15 ระดับสูง

คู่มือ MAVLink กำหนดให้เฟรมที่ลงลายเซ็นตั้งบิตแรกของ incompat flags (0x01) และต่อท้ายด้วยส่วนลายเซ็น 13 ไบต์:

  • Link ID 1 ไบต์ แยกช่องทาง เช่น วิทยุกับ LTE
  • เวลา (timestamp) 6 ไบต์ นับหน่วยละ 10 ไมโครวินาทีตั้งแต่ 1 มกราคม 2015 GMT
  • ลายเซ็น 6 ไบต์ คือ 48 บิตแรกของ SHA-256 ของกุญแจลับ 32 ไบต์ต่อด้วยส่วนหัว ข้อมูล CRC link ID และเวลา
แถบแสดงเฟรม MAVLink 2 ที่ลงลายเซ็น เรียงจากซ้ายไปขวา ส่วนหัว 10 ไบต์ ข้อมูล 0 ถึง 255 ไบต์ CRC 2 ไบต์ Link ID 1 ไบต์ เวลา 6 ไบต์ และลายเซ็น 6 ไบต์ วงเล็บใต้สามส่วนสุดท้ายเขียนว่าส่วนลายเซ็น 13 ไบต์
ภาพที่ 1 โครงเฟรม MAVLink 2 ที่ลงลายเซ็น

กฎป้องกันการส่งซ้ำ (replay) ตามคู่มือ: เวลาต้องมากกว่าข้อความก่อนหน้าในสตรีมเดียวกัน (system ID, component ID, link ID) และข้อความที่เวลาเก่ากว่าเวลาเครื่องรับเกิน 1 นาทีต้องถูกปฏิเสธ ถ้าไม่มีกฎนี้ ผู้โจมตีบันทึกคำสั่งลงจอดที่ถูกต้องไว้แล้วส่งซ้ำภายหลังได้ ส่วนข้อความที่ไม่ลงลายเซ็น ระบบกำหนดเองว่าจะรับชนิดใด เช่น RADIO_STATUS จากวิทยุของตัวเอง นอกนั้นควรปฏิเสธ คู่มือยังเตือนว่ากุญแจต้องไม่ปรากฏในพารามิเตอร์หรือ log

ตัวอย่างที่ 1 ลงและตรวจลายเซ็นเฟรม HEARTBEAT

กุญแจสร้างจากวลีตัวอย่างเพื่อการสอนเท่านั้น ของจริงต้องสุ่มจากแหล่งสุ่มที่ปลอดภัย

import hashlib
import struct

def crc_x25(data, crc=0xFFFF):
    for b in data:
        tmp = b ^ (crc & 0xFF)
        tmp = (tmp ^ (tmp << 4)) & 0xFF
        crc = ((crc >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4)) & 0xFFFF
    return crc

KEY = hashlib.sha256(b"lesson-demo-passphrase").digest()   # 32 ไบต์ สำหรับการสอนเท่านั้น
HEARTBEAT = struct.pack("<IBBBBB", 0, 2, 3, 0x81, 4, 3)     # custom_mode, type, autopilot, base_mode, status, version

def sign(seq, payload, ts, link_id=0, sysid=1, compid=1, msgid=0, crc_extra=50):
    hdr = bytes([0xFD, len(payload), 0x01, 0x00, seq, sysid, compid]) + msgid.to_bytes(3, "little")
    crc = crc_x25(hdr[1:] + payload + bytes([crc_extra]))
    tail = struct.pack("<H", crc) + bytes([link_id]) + ts.to_bytes(6, "little")
    return hdr + payload + tail + hashlib.sha256(KEY + hdr + payload + tail).digest()[:6]

last_ts = {}
def verify(frame, now):
    body, sig = frame[:-6], frame[-6:]
    if hashlib.sha256(KEY + body).digest()[:6] != sig:
        return "reject: bad signature"
    ts = int.from_bytes(body[-6:], "little")
    stream = (body[5], body[6], body[-7])                    # system ID, component ID, link ID
    if stream in last_ts and ts <= last_ts[stream]:
        return "reject: replayed or out-of-order timestamp"
    if ts < now - 6_000_000:                                 # 1 นาที = 6,000,000 หน่วย 10 µs
        return "reject: older than 1 minute"
    last_ts[stream] = ts
    return "accept"

now = 123_456_839
f1 = sign(7, HEARTBEAT, 123_456_789)
print(f"frame {len(f1)} bytes: {f1.hex()}")
print("first delivery   ->", verify(f1, now))
print("same frame again ->", verify(f1, now))
tampered = bytearray(sign(8, HEARTBEAT, 123_456_800))
tampered[13] ^= 0x01                                         # เปลี่ยน 1 บิตในข้อมูล
print("tampered payload ->", verify(bytes(tampered), now))
print("old frame, link 1->", verify(sign(9, HEARTBEAT, now - 7_000_000, link_id=1), now))
frame 34 bytes: fd0901000701010000000000000002038104033bac0015cd5b070000c82d318a978f
first delivery   -> accept
same frame again -> reject: replayed or out-of-order timestamp
tampered payload -> reject: bad signature
old frame, link 1-> reject: older than 1 minute

เฟรมยาว 10 + 9 + 2 + 13 = 34 ไบต์ ผู้สอนตรวจแล้วว่าไบต์ที่ได้ตรงกับเฟรมที่ pymavlink 2.4.50 สร้างเมื่อใช้กุญแจ เวลา และลำดับเดียวกัน การแก้ข้อมูลเพียงบิตเดียวทำให้ลายเซ็นไม่ตรง และเฟรมเดิมที่ส่งซ้ำถูกปฏิเสธเพราะเวลาไม่เพิ่มขึ้น

ยืนยันตัวตนไม่เท่ากับเข้ารหัส

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

  • บนเครือข่าย IP อย่าง LTE ใช้ DTLS 1.3 (RFC 9147) สำหรับ UDP หรือ TLS 1.3 (RFC 8446) สำหรับ TCP ซึ่งทั้งเข้ารหัสและยืนยันตัวตน
  • ถ้าออกแบบเองระดับแพ็กเก็ต ใช้โหมดที่ทั้งเข้ารหัสและยืนยันตัวตน เช่น AES-GCM ตาม NIST SP 800-38D ซึ่งเตือนว่าการใช้ค่า IV ซ้ำกับกุญแจเดิมแม้ครั้งเดียวก็อาจเปิดทางให้ปลอมข้อความได้ ความสำคัญเกือบเท่าการเก็บกุญแจเป็นความลับ
  • การจัดการกุญแจ กำหนดว่าใครสร้าง แจกจ่ายอย่างไร เก็บที่ไหน เปลี่ยนเมื่อใด และเพิกถอนอย่างไรเมื่อเครื่องหาย เป็นส่วนที่มักพลาดมากกว่าอัลกอริทึม

C2 สองช่องทาง

การใช้วิทยุและ LTE คู่กันเพิ่มความพร้อมใช้งาน แต่ต้องระวัง ความล้มเหลวร่วม (common-mode failure) เช่น ไฟดับที่ศูนย์ควบคุมซึ่งทำให้ทั้งสองช่องทางหายพร้อมกัน RTCA DO-362 กำหนดสมรรถนะขั้นต่ำของ C2 ภาคพื้น และ DO-400 ให้แนวทางขั้นตอนเมื่อ C2 ขาด ซึ่งยังจำเป็นแม้มีสองช่องทาง

อากาศยานทางซ้าย GCS ทางขวาบน เซิร์ฟเวอร์ C2 ตรงกลางล่าง ลูกศรสีฟ้าสองทางระหว่างอากาศยานกับ GCS เขียนว่าวิทยุ C2 ลงลายเซ็น ลูกศรสีม่วงจากอากาศยานไปเซิร์ฟเวอร์ C2 เขียนว่า LTE และ DTLS 1.3 แล้วจากเซิร์ฟเวอร์ไป GCS เขียนว่า TLS 1.3 กล่องสีทองเขียนว่ากุญแจอยู่ที่อากาศยาน GCS และเซิร์ฟเวอร์
ภาพที่ 2 สถาปัตยกรรม C2 สองช่องทางและจุดเก็บกุญแจ

ตัวอย่างที่ 2 ความพร้อมใช้งานของ C2

ค่าความพร้อมใช้งานเป็นค่าสมมติจากสถิติเส้นทาง เที่ยวบินละ 30 นาที

A_RADIO, A_LTE, P_COMMON = 0.97, 0.95, 0.002
FLIGHT_MIN = 30

options = {
    "radio only": A_RADIO,
    "radio + LTE (independent)": 1 - (1 - A_RADIO) * (1 - A_LTE),
    "radio + LTE with common mode": (1 - P_COMMON) * (1 - (1 - A_RADIO) * (1 - A_LTE)),
}
for name, a in options.items():
    print(f"{name:<30} availability {a:.4f}  expected outage {(1 - a) * FLIGHT_MIN * 60:5.1f} s per flight")
radio only                     availability 0.9700  expected outage  54.0 s per flight
radio + LTE (independent)      availability 0.9985  expected outage   2.7 s per flight
radio + LTE with common mode   availability 0.9965  expected outage   6.3 s per flight

ช่องทางที่สองลดเวลาที่ลิงก์หายลงมาก แต่ความล้มเหลวร่วมเพียง 0.2% ทำให้เวลาหายเพิ่มกว่าสองเท่าของกรณีอิสระ ต้องแยกไฟฟ้า เครือข่าย และสถานที่ของสองช่องทางให้มากที่สุด

ปฏิบัติการประจำโมดูล

ปฏิบัติการ: เปิดใช้ลายเซ็นและทดสอบใน SITL

  1. รันโค้ดตัวอย่างที่ 1 แล้วเทียบกับเฟรมที่ pymavlink สร้างด้วยกุญแจและเวลาเดียวกัน
  2. เปิดใช้ลายเซ็น MAVLink ใน SITL ตามคู่มือของ ArduPilot หรือ PX4 และโปรแกรม GCS ที่ใช้
  3. ส่งคำสั่งจากสคริปต์ที่ไม่มีกุญแจ ตรวจว่าถูกปฏิเสธ และบันทึก log
  4. ส่งเฟรมที่บันทึกไว้ซ้ำใน loopback ตรวจว่ากฎป้องกันการส่งซ้ำทำงาน
  5. เขียนแผนจัดการกุญแจของเครือข่ายส่งเวชภัณฑ์ และคำนวณความพร้อมใช้งานด้วยตัวอย่างที่ 2

ข้อผิดพลาดที่พบบ่อย

ระวัง

  • คิดว่าลายเซ็นเข้ารหัสข้อมูลให้
  • รับข้อความที่ไม่ลงลายเซ็นทุกชนิด เพื่อความสะดวก
  • เก็บกุญแจในพารามิเตอร์หรือ log
  • ใช้ IV ซ้ำใน AES-GCM
  • คิดว่ามีสองช่องทางแล้วไม่ต้องมีขั้นตอนเมื่อ C2 ขาด

สรุป

  • ลายเซ็น MAVLink 2 ยาว 13 ไบต์ ได้จาก SHA-256 ของกุญแจ 32 ไบต์และเนื้อเฟรม ตัดเหลือ 6 ไบต์
  • เวลาที่ต้องเพิ่มขึ้นในแต่ละสตรีมและเกณฑ์ 1 นาทีช่วยกันการส่งซ้ำ
  • ลายเซ็นยืนยันตัวตนแต่ไม่ปิดบังเนื้อหา ต้องใช้ DTLS/TLS หรือ AES-GCM เมื่อต้องการความลับ
  • C2 สองช่องทางเพิ่มความพร้อมใช้งาน แต่ต้องลดความล้มเหลวร่วมและยังต้องมีขั้นตอนเมื่อ C2 ขาด

แบบฝึกตรวจความเข้าใจ

  1. ส่วนลายเซ็นของ MAVLink 2 ประกอบด้วยอะไรบ้าง รวมกี่ไบต์
  2. เวลา 1 วินาทีเท่ากับกี่หน่วยของ timestamp ใน MAVLink
  3. ทำไมเฟรมที่ถูกต้องทุกไบต์แต่ส่งซ้ำจึงถูกปฏิเสธ
  4. ลิงก์สองช่องทางมีความพร้อมใช้งาน 0.9 และ 0.9 อิสระกัน รวมเป็นเท่าใด
  5. ผู้ดักสัญญาณวิทยุที่ลงลายเซ็นแล้วยังเห็นอะไรได้
เฉลย
  1. Link ID 1 ไบต์ เวลา 6 ไบต์ ลายเซ็น 6 ไบต์ รวม 13 ไบต์
  2. 100,000 หน่วย (หน่วยละ 10 µs)
  3. เวลาของเฟรมไม่มากกว่าเวลาล่าสุดของสตรีมเดียวกัน
  4. เนื้อหาทั้งหมด เช่น ตำแหน่งและสถานะ เพราะลายเซ็นไม่ได้เข้ารหัส

สรุปสูตรสำคัญ

ลายเซ็น MAVLink 2
ความพร้อมใช้งานของสองช่องทาง

แหล่งอ้างอิงหลัก

  1. MAVLink Development Team. Message signing (authentication). MAVLink developer guide. link
  2. Dworkin, M. (2007). Recommendation for block cipher modes of operation: Galois/Counter Mode (GCM) and GMAC (NIST SP 800-38D). National Institute of Standards and Technology. link
  3. Rescorla, E., Tschofenig, H., & Modadugu, N. (2022). The Datagram Transport Layer Security (DTLS) protocol version 1.3 (RFC 9147). RFC Editor. link
  4. Rescorla, E. (2018). The Transport Layer Security (TLS) protocol version 1.3 (RFC 8446). RFC Editor. link
  5. RTCA. (2016). Command and control (C2) data link minimum operational performance standards (MOPS) (terrestrial) (DO-362). link
  6. RTCA. (2023). Guidance material: Lost C2 link procedures (DO-400). link

อ่านเพิ่มเติม

ศึกษาหน่วยความรู้ที่กำหนดล่วงหน้า ดูสื่อประกอบ และทำ quiz ประจำโมดูล

ในชั้นเรียน / ภาคสนาม

ปฏิบัติการเข้มข้นในแล็บและภาคสนาม บันทึกผลลงสมุดปฏิบัติการ

หลักฐานการเรียนรู้: สมุดปฏิบัติการที่อาจารย์ลงนาม

แบบทดสอบประจำโมดูล

แบบทดสอบนี้ใช้ตรวจความเข้าใจ (formative) ไม่ใช่การสอบเก็บคะแนน

โดเมนความรู้: การสื่อสาร เครือข่าย และ IoT · กฎหมาย ความปลอดภัย และความเสี่ยง