ป้องกันการแชร์ license key ด้วย Device Fingerprint

อ่าน 7 นาที

ทำไม license key อย่างเดียวไม่พอ และวิธีผูก license กับเครื่องด้วย device fingerprint เพื่อจำกัดจำนวนที่นั่ง (seat) พร้อมตัวอย่างโค้ดทุกแพลตฟอร์ม

ปัญหาคลาสสิกของการขายซอฟต์แวร์แบบ license key คือ ลูกค้าซื้อ 1 คีย์แล้วเอาไปแชร์ให้เพื่อนทั้งออฟฟิศ การมีแค่ “คีย์ที่ถูกต้อง” ไม่พอ — เพราะคีย์ก๊อปปี้ได้ไม่จำกัด ทางออกคือผูก license เข้ากับ “เครื่อง” ด้วย device fingerprint แล้วจำกัดจำนวนเครื่อง (seat) ต่อคีย์

Device Fingerprint คืออะไร

fingerprint คือสตริงเฉพาะของแต่ละเครื่อง (8–255 ตัวอักษร) ที่สร้างจากค่าฮาร์ดแวร์/ระบบ ที่ค่อนข้างคงที่ เช่น machine id หรือ MAC address แล้วนำมา hash ด้วย SHA-256 ก่อนส่ง แนวคิดคือ: เครื่องเดียวกันต้องได้ fingerprint เดิมเสมอ เพื่อให้การนับที่นั่งแม่นยำ

Node.js — สร้าง fingerprint
import { createHash } from "node:crypto";
import os from "node:os";

// รวมค่าเฉพาะของเครื่อง แล้ว hash ด้วย SHA-256 → hex string คงที่
const mac = Object.values(os.networkInterfaces())
  .flat()
  .find((i) => i && !i.internal && i.mac && i.mac !== "00:00:00:00:00:00")?.mac;

const fingerprint = createHash("sha256")
  .update(`${os.hostname()}|${mac ?? "no-mac"}`)
  .digest("hex");

เลือกแหล่งข้อมูลตามแพลตฟอร์ม

ค่าที่ดีควรคงที่ตลอดอายุการใช้งานบนเครื่องเดิม และไม่เปลี่ยนเมื่อรีสตาร์ต แนะนำดังนี้:

แหล่งข้อมูลที่แนะนำ
// Windows  → MachineGuid (HKLM\SOFTWARE\Microsoft\Cryptography)
// macOS    → IOPlatformUUID (ioreg -rd1 -c IOPlatformExpertDevice)
// Linux    → /etc/machine-id หรือ /var/lib/dbus/machine-id
// ทุกค่าให้ hash ด้วย SHA-256 ก่อนส่งเสมอ (อย่าส่งค่าดิบ)

ข้อควรระวัง: อย่าใช้ค่าที่เปลี่ยนบ่อย (เช่น IP address) เพราะจะทำให้ activate กินที่นั่งใหม่ทุกครั้ง และอย่าส่งค่าดิบ — hash ก่อนเสมอเพื่อความเป็นส่วนตัว

จำกัดจำนวนที่นั่งด้วย max_activations

เมื่อสร้าง policy ใน KeyThai คุณกำหนด max_activations ได้ เช่น 3 เครื่อง ทุกครั้งที่เรียก activate ด้วย fingerprint ใหม่ ระบบจะเพิ่ม machine_count และเมื่อเกินจะตอบกลับ error SEAT_LIMIT_REACHED

JavaScript (SDK keythai)
import { KeyThaiClient } from "keythai";

const client = new KeyThaiClient({ apiKey: "kt_live_xxxxxxxxxxxx" });
const key = "KEYT-AB12-3C4D-5E6F-7G8H-9J0K";

// fingerprint เดิม → activate ซ้ำไม่กินที่นั่งเพิ่ม (idempotent)
const res = await client.activate(key, { fingerprint, platform: "windows" });
console.log(res.machine_count, "/", res.max_activations, "ที่นั่ง");
// เครื่องที่ 4 (เกิน max_activations) จะได้ error SEAT_LIMIT_REACHED

เพราะ activate เป็น idempotent ต่อ fingerprint การที่ลูกค้าเปิดแอปซ้ำบนเครื่องเดิมจึงไม่กินที่นั่งเพิ่ม — ที่นั่งจะถูกใช้ก็ต่อเมื่อเป็นเครื่อง (fingerprint) ใหม่จริง ๆ เท่านั้น

ย้ายเครื่อง: คืนที่นั่งก่อน

เมื่อลูกค้าเปลี่ยนเครื่อง ให้คืนที่นั่งของเครื่องเก่าก่อน เพื่อไม่ให้เต็มโควตา ทำได้ทั้งจากฝั่งแอป (deactivate) หรือจากระบบหลังบ้านของคุณผ่าน Management API (removeMachine):

JavaScript
// ผู้ใช้เปลี่ยนเครื่อง → คืนที่นั่งเครื่องเก่าก่อน
await client.removeMachine(key, oldFingerprint);   // Management API
// หรือฝั่งแอปเอง:
await client.deactivate(key, { fingerprint: oldFingerprint });

ด้วยแนวทางนี้ ลูกค้า 1 คีย์จะใช้ได้สูงสุดตามจำนวนที่นั่งที่คุณตั้งไว้ การแชร์คีย์ให้คนทั้งออฟฟิศ จึงทำไม่ได้อีกต่อไป อ่านต่อเรื่อง ตรวจ license แบบ offline ด้วย Ed25519 เพื่อกันการปลอม response ระดับถัดไป

พร้อมปกป้องซอฟต์แวร์ของคุณแล้วหรือยัง?

เริ่มต้นฟรี ไม่ต้องใช้บัตรเครดิต ออก license key แรกของคุณได้ในไม่กี่นาที