Trong nhiều năm, cookie là công cụ chính để nhận diện người dùng trên website. Tuy nhiên, với sự siết chặt của các trình duyệt (ITP, ETP, SameSite, block third-party cookie), cookie ngày càng trở nên kém ổn định và không đáng tin cậy cho các hệ thống analytics, anti-spam hay đo lường traffic thật.

Một giải pháp được cộng đồng sử dụng rộng rãi là FingerprintJS (open-source). Dù thường bị gọi là “bản cơ bản”, nhưng nếu hiểu đúng và thiết kế backend hợp lý, FingerprintJS OSS hoàn toàn đủ dùng cho phần lớn website thực tế.

Bài viết này chia sẻ cách tiếp cận đúng và thiết kế database fingerprint theo hướng thực chiến – nhẹ – dễ scale.


1. FingerprintJS OSS có thực sự “cơ bản”?

FingerprintJS OSS tạo fingerprint bằng cách thu thập các tín hiệu phía trình duyệt như:

  • User-Agent
  • Canvas / WebGL
  • Screen, timezone, language
  • AudioContext
  • Fonts, hardware hints

Sau đó, các tín hiệu này được hash để tạo ra một chuỗi định danh gọi là visitorId.

Người ta thường gọi FingerprintJS OSS là “cơ bản” không phải vì nó yếu, mà vì:

  • Chỉ chạy client-side
  • Không có dữ liệu server-side (IP intelligence, network behavior)
  • Không cross-device

Đây là giới hạn thiết kế, không phải nhược điểm kỹ thuật.

👉 Với web tin tức, blog SEO, anti-spam, đo user ẩn danh, những tín hiệu này là quá đủ.


2. Fingerprint không phải User – sai lầm phổ biến

Một sai lầm rất thường gặp:

Coi visitorId = 1 user vĩnh viễn

Thực tế:

  • Fingerprint có thể thay đổi
  • Trình duyệt update
  • GPU / driver đổi
  • Extension privacy can thiệp

👉 Vì vậy:

  • Fingerprint chỉ là một tín hiệu
  • User thực cần được suy luận từ nhiều tín hiệu kết hợp

Đây chính là lý do cần thiết kế database đúng ngay từ đầu.


3. Triết lý thiết kế hệ thống fingerprint

Nguyên tắc cốt lõi:

  • ❌ Không phụ thuộc cookie
  • ❌ Không lưu dữ liệu nhạy cảm thô
  • ✅ Chấp nhận fingerprint thay đổi
  • ✅ Gộp nhiều fingerprint thành một visitor logic
  • ✅ Có khả năng reconcile phía server

4. Kiến trúc tổng thể

visitors
├── visitor_fingerprints
├── visitor_sessions
└── visitor_events (optional)
  • visitors: đại diện cho người dùng logic
  • visitor_fingerprints: lưu các fingerprint đã từng thấy
  • visitor_sessions: hành vi truy cập
  • visitor_events: dùng cho anti-spam nâng cao (tuỳ chọn)

5. Schema chi tiết

5.1 Bảng visitors – user logic

CREATE TABLE visitors (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  first_seen DATETIME NOT NULL,
  last_seen DATETIME NOT NULL,
  total_sessions INT UNSIGNED DEFAULT 0,
  total_pages INT UNSIGNED DEFAULT 0,
  risk_score TINYINT UNSIGNED DEFAULT 0,
  status ENUM('normal','suspicious','blocked') DEFAULT 'normal',
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Bảng này không phụ thuộc fingerprint.
Nó đại diện cho một người dùng logic hoặc một thiết bị ổn định.


5.2 Bảng visitor_fingerprints – lõi hệ thống

CREATE TABLE visitor_fingerprints (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  visitor_id BIGINT UNSIGNED NOT NULL,
  fingerprint_id CHAR(32) NOT NULL,
  user_agent_hash CHAR(40) NOT NULL,
  ip_prefix VARBINARY(8) NOT NULL,
  device_type ENUM('desktop','mobile','tablet','bot','unknown'),
  confidence TINYINT UNSIGNED DEFAULT 100,
  first_seen DATETIME NOT NULL,
  last_seen DATETIME NOT NULL,
  seen_count INT UNSIGNED DEFAULT 1,
  INDEX idx_fingerprint (fingerprint_id),
  INDEX idx_ip_prefix (ip_prefix),
  INDEX idx_visitor (visitor_id)
);

Một visitor:

  • Có thể có nhiều fingerprint
  • Fingerprint đổi nhưng visitor vẫn giữ nguyên

Đây là chìa khoá để hệ thống không bị vỡ dữ liệu theo thời gian.


5.3 Bảng visitor_sessions – phân biệt user thật

CREATE TABLE visitor_sessions (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  visitor_id BIGINT UNSIGNED NOT NULL,
  session_key CHAR(40) NOT NULL,
  ip_address VARBINARY(16) NOT NULL,
  started_at DATETIME NOT NULL,
  ended_at DATETIME DEFAULT NULL,
  page_views INT UNSIGNED DEFAULT 1,
  duration INT UNSIGNED DEFAULT 0,
  is_bounce TINYINT(1) DEFAULT 1,
  INDEX idx_visitor (visitor_id),
  INDEX idx_session (session_key)
);

Bảng này giúp:

  • Phân biệt reload vs user thật
  • Tính time-on-site
  • Phát hiện bot đọc quá nhanh

5.4 (Tuỳ chọn) visitor_events

Dùng khi cần anti-spam mạnh:

CREATE TABLE visitor_events (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  visitor_id BIGINT UNSIGNED NOT NULL,
  event_type VARCHAR(32),
  event_value VARCHAR(255),
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Ví dụ event:

  • submit_comment
  • search
  • click_ad
  • scroll_depth

6. Logic reconcile fingerprint (quan trọng nhất)

Khi client gửi dữ liệu lên server:

{
  "fingerprint": "abc123",
  "user_agent": "...",
  "ip": "1.2.3.4"
}

Server xử lý theo thứ tự:

  1. Tìm fingerprint_id
    • Có → lấy visitor cũ
  2. Không có → tìm theo:
    • ip_prefix
    • user_agent_hash
    • last_seen gần đây
  3. Match → gán fingerprint mới cho visitor cũ
  4. Không match → tạo visitor mới

👉 Fingerprint đổi không làm mất lịch sử user.


7. Risk score & anti-spam

Ví dụ tính điểm rủi ro:

Điều kiệnĐiểm
>50 page / 5 phút+30
>3 fingerprint / 24h+20
Headless UA+40
Không canvas+25

Khi vượt ngưỡng:

  • Gắn cờ suspicious
  • Hạn chế action
  • Hoặc block mềm

8. Vì sao mô hình này đủ mạnh cho web SEO / tin tức?

  • Không cần cookie
  • Không phụ thuộc login
  • Không xâm phạm privacy
  • Chịu được fingerprint thay đổi
  • Dữ liệu không vỡ theo thời gian
  • Scale tốt trên MySQL

👉 Với phần lớn website thực tế, mô hình này đạt 80–90% hiệu quả của các giải pháp thương mại, nhưng hoàn toàn miễn phí.


9. Kết luận

FingerprintJS OSS không hề “yếu”.
Nó chỉ đúng với mục đích thiết kế của nó.

Nếu:

  • Không coi fingerprint là user tuyệt đối
  • Thiết kế database đúng
  • Reconcile phía server thông minh

👉 Bạn sẽ có một hệ thống nhận diện user ổn định, bền vững và đủ mạnh cho nhiều năm sử dụng.