# คู่มือการเปิดใช้งานระบบยืนยันตัวตนสำหรับวิดีโอที่เข้ารหัสแบบ ClearKey

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

ClearKey เป็นระบบ DRM ที่มีความซับซ้อนน้อยกว่า Widevine หรือ FairPlay แต่ยังคงให้การป้องกันพื้นฐานที่เพียงพอ

เอกสารฉบับนี้จะอธิบายถึงจุดอ่อนของระบบ ClearKey ที่มีอยู่ และแนวทางการเพิ่มกลไกการยืนยันตัวตน (Authentication) เพื่อเสริมสร้างความปลอดภัยให้กับระบบ


# ภาพรวมของระบบ ClearKey ที่มีอยู่

# หลักการทำงานพื้นฐาน

ระบบ ByteArk Stream รองรับการประมวลผลวิดีโอที่เข้ารหัสแบบ Clear Key ด้วยอัลกอริทึม AES-128 สำหรับวิดีโอในรูปแบบ HLS (HTTP Live Streaming) ผู้ชมวิดีโอที่ถูกเข้ารหัสจะไม่สามารถรับชมได้หากไม่ได้รับกุญแจ (Key) ที่ใช้ในการเข้ารหัสเพื่อใช้ในการถอดรหัสเสียก่อน ถึงแม้ว่าผู้ชมจะดาวน์โหลดวิดีโอดังกล่าวมาด้วยวิธีใดก็ตาม

# โครงสร้าง HLS กับการเข้ารหัส

ในรูปแบบ HLS วิดีโอจะถูกแบ่งออกเป็นส่วนย่อย ๆ เรียกว่า "Segment" และไฟล์ Manifest จะมีข้อมูลอ้างอิงถึงตำแหน่งของกุญแจที่ใช้ในการถอดรหัส

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-KEY:METHOD=AES-128,URI="https://key-server.example.com/key",IV=0x...
#EXTINF:10.0,
segment1.ts
#EXTINF:10.0,
segment2.ts
1
2
3
4
5
6
7
8

จากตัวอย่าง #EXT-X-KEY ระบุว่าวิดีโอถูกเข้ารหัสด้วย AES-128 และกุญแจสามารถขอได้จาก URL ที่ระบุ


# จุดอ่อนของระบบปัจจุบัน

# การขาดกลไกการยืนยันตัวตน

แม้ว่าระบบ ClearKey จะให้การป้องกันพื้นฐานผ่านการเข้ารหัส แต่ก็ยังมีจุดอ่อนสำคัญ คือ การขอกุญแจไม่มีการตรวจสอบสิทธิ์การเข้าถึง

# ปัญหาที่เกิดขึ้น

  1. การเข้าถึงกุญแจโดยไม่ได้รับอนุญาต - ผู้ไม่หวังดีสามารถขอกุญแจถอดรหัสได้โดยตรงหากทราบ URL
  2. การแบ่งปันกุญแจ - ผู้ใช้ที่ได้รับสิทธิ์สามารถนำกุญแจไปแบ่งปันให้ผู้อื่นได้
  3. ขาดการควบคุมการเข้าถึง - ไม่สามารถจำกัดสิทธิ์ตามระยะเวลา จำนวนครั้ง หรือเพิกถอนสิทธิ์ได้

# แผนภาพลำดับขั้น: ระบบเดิม

# ขั้นตอนการทำงานของระบบ ClearKey เดิม

# คำอธิบายขั้นตอนการทำงานของระบบเดิม

# ขั้นตอนที่ 1: การดึงไฟล์ Manifest

ผู้ชมจะดำเนินการขอไฟล์ Manifest จาก Manifest Server เพื่อรับข้อมูลเกี่ยวกับวิดีโอที่ต้องการรับชม

# ขั้นตอนที่ 2: การดึงกุญแจ (จุดอ่อนหลัก)

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

# ขั้นตอนที่ 3: การเล่นวิดีโอ

หลังจากได้รับกุญแจแล้ว ผู้ชมสามารถถอดรหัสและเล่นวิดีโอได้ทันที


# แผนภาพลำดับขั้น: ระบบใหม่ที่มีการยืนยันตัวตน

# แนวทางการแก้ไขจุดอ่อน

เพื่อแก้ไขจุดอ่อนดังกล่าว ByteArk ได้พัฒนาระบบใหม่ที่เพิ่มกลไกการยืนยันตัวตน (Authentication) เข้าไปในกระบวนการหลัก โดยมีหลักการสำคัญดังนี้:

  1. การสร้าง Key Pair: สร้างคู่กุญแจ (Public/Private Key) เพื่อใช้ในการลงนามดิจิทัล
  2. การยืนยันตัวตน: ตรวจสอบสิทธิ์ผู้ใช้ก่อนอนุญาตให้เข้าถึงเนื้อหา
  3. การจัดการ Session: ควบคุมระยะเวลาและขอบเขตการเข้าถึง
  4. การตรวจสอบโดเมน: จำกัดการเข้าถึงจากแหล่งที่ได้รับอนุญาตเท่านั้น

# แผนภาพลำดับขั้นของระบบใหม่

# คำอธิบายขั้นตอนการทำงานของระบบใหม่

# ขั้นตอนที่ 1: การตั้งค่าคู่กุญแจ (Setup Key Pair)

ในขั้นตอนนี้ ลูกค้าจะดำเนินการสร้าง Key Pair สำหรับการยืนยันตัวตน:

  1. ส่งคำขอสร้าง Key Pair ไปยัง Stream API พร้อมกับ PAT และ Playback Channel ID
  2. รับ Private Key และ Keypair ID กลับมา
  3. เก็บ Private Key ไว้อย่างปลอดภัยเพื่อใช้ในการลงนาม JWT Token

# ขั้นตอนที่ 2: การยืนยันตัวตน (Authentication)

ขั้นตอนนี้เป็นหัวใจสำคัญของระบบใหม่ โดยมีการตรวจสอบสิทธิ์ผู้ใช้ก่อนอนุญาตให้เข้าถึงเนื้อหา:

  1. ผู้ชมส่งคำขอยืนยันตัวตนไปยัง Backend ของลูกค้า (ใช้ OAuth, Username/Password หรือวิธีการอื่นตามที่ลูกค้ากำหนด)
  2. Backend ตรวจสอบข้อมูลผู้ใช้ และสร้าง JWT Token โดยลงนามด้วย Private Key
  3. ผู้ชมส่ง JWT Token ไปยัง Key Server ผ่าน SDK ด้วยฟังก์ชัน initAuth()
  4. หากถูกต้อง จะได้รับ Session และ Refresh Token

# ขั้นตอนที่ 3: การดึงข้อมูล Manifest

หลังจากยืนยันตัวตนสำเร็จแล้ว ผู้ชมสามารถขอข้อมูลวิดีโอได้:

  1. ขอไฟล์ Playlist จาก Manifest Server
  2. รับ Playlist กลับมา พร้อม Key Server URL
  3. ขอ prog_index.m3u8 โดยระบุ x_ark_origin (หรือใช้ค่า Default)

# ขั้นตอนที่ 4: การดึงกุญแจ (Key Fetch)

ในขั้นตอนสุดท้าย ผู้ชมสามารถขอกุญแจถอดรหัสได้:

  1. ส่งคำขอไปยัง Key Server โดยแนบ Session ที่ได้รับ
  2. ได้รับกุญแจถอดรหัสกลับมา
  3. เมื่อ Session ใกล้หมดอายุ เรียก renewSession() เพื่อต่ออายุ

# API สำหรับ Passport Key Server

# การยืนยันตัวตนและการอนุญาต

ทุก Endpoint ต้องส่ง Request Headers ดังนี้:

Header ค่า จำเป็น คำอธิบาย
Authorization Bearer <access_token> ใช่ Access token ของผู้ใช้ที่ผ่านการยืนยันตัวตนแล้ว
x-byteark-team <team_identifier> ใช่ Team identifier ของผู้เรียก

# 1. การสร้าง Key Pair สำหรับ Playback Channel

สร้างคู่กุญแจ ECDSA สำหรับ Playback Channel เพื่อใช้ยืนยันตัวตน

# Endpoint

POST /playback-channels/:playbackChannelId/key-pair
1

# Path Parameters

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
passportKeyServerId string ใช่ ID ของ Passport Key Server

# Request Body

Content-Type: application/json

ฟิลด์ ชนิด จำเป็น คำอธิบาย
enabledCookieAuth boolean ใช่ เปิด (true) หรือปิด (false) Cookie Authentication

# ตัวอย่าง

{
  "enabledCookieAuth": true
}
1
2
3

# Response

# 200 OK

ฟิลด์ ชนิด คำอธิบาย
id string ID ของ record
playbackChannelId string ID ของ Playback Channel
allowDomains string[] รายการโดเมนที่อนุญาต
defaultDomain string โดเมนเริ่มต้น
passportClearKeyServerId string Passport Clear Key Server ID
enabledCookieAuth boolean สถานะการเปิด/ปิด Cookie Authentication ปัจจุบัน

# ตัวอย่าง

{
  "id": "65a1b2c3d4e5f67890abcdef",
  "playbackChannelId": "pc-abc123",
  "allowDomains": ["example.com", "cdn.example.com"],
  "defaultDomain": "example.com",
  "passportClearKeyServerId": "pcks-def456",
  "enabledCookieAuth": true
}
1
2
3
4
5
6
7
8

# 3. การอัปเดตโดเมนที่อนุญาต

อัปเดตรายการโดเมนที่อนุญาตสำหรับ Passport Key Server ที่ระบุ

# Endpoint

PUT /passport-keyservers/:passportKeyServerId/allow-domains
1

# Path Parameters

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
passportKeyServerId string ใช่ ID ของ Passport Key Server

# Request Body

Content-Type: application/json

ฟิลด์ ชนิด จำเป็น คำอธิบาย
allowDomains string[] ใช่ รายการโดเมนที่อนุญาต

# ตัวอย่าง

{
  "allowDomains": ["example.com", "cdn.example.com"]
}
1
2
3

# Response

# 200 OK

ฟิลด์ ชนิด คำอธิบาย
id string ID ของ record
defaultDomain string โดเมนเริ่มต้น
allowDomains string[] รายการโดเมนที่อนุญาต (อัปเดตแล้ว)
enabledCookieAuth boolean สถานะการเปิด/ปิด Cookie Authentication ปัจจุบัน

# ตัวอย่าง

{
  "id": "65a1b2c3d4e5f67890abcdef",
  "defaultDomain": "example.com",
  "allowDomains": ["example.com", "cdn.example.com"],
  "enabledCookieAuth": true
}
1
2
3
4
5
6

# 4. การเพิกถอน/ยกเลิกการเพิกถอน Key Pair

เพิกถอนการใช้งานของ Key Pair บน Passport Key Server

# Endpoint

PUT /passport-keyservers/key-pairs/:keyPairId/revoked
1

# Path Parameters

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
keyPairId string ใช่ ID ของ Key Pair

# Request Body

Content-Type: application/json

ฟิลด์ ชนิด จำเป็น คำอธิบาย
revoked boolean ใช่ เพิกถอน (true) หรือยกเลิกการเพิกถอน (false) Key Pair

# ตัวอย่าง

{
  "revoked": true
}
1
2
3

# Response

# 200 OK

ฟิลด์ ชนิด คำอธิบาย
keyPairId string ID ของ Key Pair
revoked boolean สถานะการเพิกถอนปัจจุบัน

# ตัวอย่าง

{
  "keyPairId": "65a1b2c3d4e5f67890abcdef",
  "revoked": true
}
1
2
3
4

# 404 Not Found

ส่งกลับเมื่อไม่พบ Key Pair ที่ระบุ

ฟิลด์ ชนิด คำอธิบาย
message string ข้อความแสดงข้อผิดพลาด

# ข้อกำหนดการตั้งค่าโดเมนสำหรับ API Session

[!IMPORTANT] หากต้องการใช้งาน API Session (Cookie-based Authentication) โดเมนของ Key Server และโดเมนของ Client จะต้องอยู่ภายใต้ Top-Level Domain เดียวกัน

# เหตุผลที่ต้องตั้งค่าโดเมนให้ตรงกัน

ระบบ Session ใช้ HTTP Cookie (session_token) ในการเก็บ Token โดย Cookie จะถูกตั้งค่าโดเมนเป็น Root Domain ของ Key Server เช่น:

Hostname ของ Key Server Cookie Domain ที่ถูกตั้งค่า
api.example.com .example.com
key-server.byteark.com .byteark.com
localhost localhost

เนื่องจาก Browser จะส่ง Cookie กลับไปยัง Server เฉพาะโดเมนที่ตรงกันเท่านั้น ดังนั้นหาก Client อยู่คนละ Top-Level Domain กับ Key Server, Cookie จะไม่ถูกส่งไปด้วย ทำให้ Session ใช้งานไม่ได้

# ตัวอย่าง

# ใช้งานได้ (โดเมนตรงกัน)

Key Server:  https://api.example.com
Client App:  https://player.example.com
→ Cookie Domain = .example.com → ใช้ร่วมกันได้
1
2
3

# ใช้งานไม่ได้ (โดเมนไม่ตรงกัน)

Key Server:  https://api.example.com
Client App:  https://player.another-site.com
→ Cookie Domain = .example.com → Browser ไม่ส่ง Cookie ให้กับ another-site.com
1
2
3

# วิธีแก้ไข

หากโดเมนของ Client ไม่ตรงกับ Key Server ให้ดำเนินการ Alias (CNAME) โดเมนของ Key Server ให้อยู่ภายใต้โดเมนเดียวกับ Client เช่น:

Client App:     https://player.mysite.com
Key Server:     https://api.example.com
→ สร้าง CNAME: key-server.mysite.com → api.example.com
→ เรียก API ผ่าน: https://key-server.mysite.com
→ Cookie Domain = .mysite.com → ใช้ร่วมกันได้
1
2
3
4
5
6

[!WARNING] หากไม่ดำเนินการ Alias โดเมน ระบบ Session จะไม่สามารถทำงานได้ เนื่องจาก Browser จะไม่ส่ง Cookie ข้ามโดเมน และการเรียก API ที่ต้องการ Session จะได้รับ HTTP 401 Unauthorized ทุกครั้ง

# สรุป

สิ่งที่ต้องดำเนินการ รายละเอียด
ตรวจสอบโดเมน ให้แน่ใจว่า Client และ Key Server อยู่ภายใต้ Top-Level Domain เดียวกัน
สร้าง CNAME (ถ้าจำเป็น) Alias โดเมนของ Key Server ให้อยู่ภายใต้โดเมนของ Client
ตั้งค่า SSL ให้แน่ใจว่าโดเมนที่ Alias มี SSL Certificate ที่ถูกต้อง
ทดสอบ Cookie ตรวจสอบว่า Cookie session_token ถูกส่งไปกับ Request ได้อย่างถูกต้อง