ป้องกันการแชร์ license key ด้วย Device Fingerprint
ทำไม 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 เดิมเสมอ เพื่อให้การนับที่นั่งแม่นยำ
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
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):
// ผู้ใช้เปลี่ยนเครื่อง → คืนที่นั่งเครื่องเก่าก่อน
await client.removeMachine(key, oldFingerprint); // Management API
// หรือฝั่งแอปเอง:
await client.deactivate(key, { fingerprint: oldFingerprint });ด้วยแนวทางนี้ ลูกค้า 1 คีย์จะใช้ได้สูงสุดตามจำนวนที่นั่งที่คุณตั้งไว้ การแชร์คีย์ให้คนทั้งออฟฟิศ จึงทำไม่ได้อีกต่อไป อ่านต่อเรื่อง ตรวจ license แบบ offline ด้วย Ed25519 เพื่อกันการปลอม response ระดับถัดไป