0

Kỹ thuật che thông tin khách hàng (Masking PII): Bảo mật dữ liệu nhạy cảm trong ứng dụng Backend hiện đại

Chào anh em!

Trong kỷ nguyên số hóa và các bộ luật bảo vệ dữ liệu cá nhân (như GDPR hay Nghị định bảo vệ dữ liệu cá nhân tại Việt Nam) ngày càng thắt chặt, việc bảo vệ thông tin định danh cá nhân của khách hàng (PII - Personally Identifiable Information) là nghĩa vụ sống còn của mọi hệ thống phần mềm.

Sẽ thế nào nếu một nhân viên hỗ trợ khách hàng (Customer Support) hoặc một lập trình viên xem log hệ thống mà nhìn thấy toàn bộ số căn cước công dân, số thẻ tín dụng hoặc số điện thoại của người dùng? Đó là một thảm họa bảo mật. Để giải quyết bài toán này, kỹ thuật Che thông tin khách hàng (Data Masking) ra đời.

Hôm nay, hãy cùng mổ xẻ xem kỹ thuật này là gì và xem phần demo thực tế cách hiện thực hóa nó trong code Backend nhé!

1. Data Masking (Che thông tin) thực chất là gì?

Data Masking là quá trình làm ẩn đi một phần dữ liệu nhạy cảm của khách hàng trước khi hiển thị nó lên giao diện người dùng, trả về qua API, hoặc ghi vào file log, nhưng vẫn giữ lại đủ thông tin để người dùng nhận diện được tài khoản của chính họ.

Các quy tắc che thông tin phổ biến:

  • Số điện thoại: 0981234567 -> 098****567 (Giữ lại 3 số đầu và 3 số cuối).
  • Email: nguyenhuyhoang@gmail.com -> ngu*****ang@gmail.com (Giữ lại vài ký tự đầu và tên miền).
  • Số căn cước / CMND: 038098123456 -> 038********6

2. Phần Demo: Hiện thực hóa hàm Masking bằng PHP / Laravel

Để anh em dễ hình dung, chúng ta sẽ xây dựng một Helper Function chuyên dụng để che số điện thoại và email, sau đó tích hợp nó vào một Resource hoặc Service của Laravel.

Bước 1: Viết hàm Masking cơ bản (Pure Function)

if (!function_exists('mask_phone')) {
    /**
     * Che số điện thoại, chỉ giữ lại 3 số đầu và 3 số cuối.
     */
    function mask_phone(?string $phone): ?string
    {
        if (empty($phone)) {
            return null;
        }

        $length = strlen($phone);
        if ($length <= 6) {
            return '***';
        }

        // Cắt lấy 3 ký tự đầu, 3 ký tự cuối và chèn dấu sao ở giữa
        $start = substr($phone, 0, 3);
        $end = substr($phone, -3);
        $maskedLength = $length - 6;

        return $start . str_repeat('*', $maskedLength) . $end;
    }
}

if (!function_exists('mask_email')) {
    /**
     * Che địa chỉ email bảo mật.
     */
    function mask_email(?string $email): ?string
    {
        if (empty($email) || !str_contains($email, '@')) {
            return '***@***.com';
        }

        [$name, $domain] = explode('@', $email);
        $nameLength = strlen($name);
        
        if ($nameLength <= 2) {
            $maskedName = substr($name, 0, 1) . '*';
        } else {
            $maskedName = substr($name, 0, 2) . str_repeat('*', $nameLength - 2);
        }

        return $maskedName . '@' . $domain;
    }
}

Bước 2: Tích hợp vào API Response (Laravel API Resource)

Thay vì trả về dữ liệu trần trụi từ Database cho client, chúng ta sẽ bọc nó lại thông qua lớp API Resource để tự động áp dụng bộ lọc che thông tin:

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            // Áp dụng kỹ thuật Masking trước khi trả về JSON cho client
            'phone' => mask_phone($this->phone), 
            'email' => mask_email($this->email),
            'created_at' => $this->created_at,
        ];
    }
}

Bước 3: Kiểm thử kết quả (Test Demo)

Khi bạn gọi API lấy thông tin người dùng:

$user = User::find(1); // Giả sử phone: "0981234567", email: "developer@hasaki.vn"
return new UserResource($user);

Dữ liệu JSON thực tế trả về cho Client:

{
    "data": {
        "id": 1,
        "name": "Nguyễn Huy Hoàng",
        "phone": "098****567",
        "email": "de********@hasaki.vn",
        "created_at": "2026-06-06T10:00:00.000000Z"
    }
}

3. Những lưu ý "sống còn" khi làm Data Masking

  • Chỉ che ở tầng hiển thị (Presentation Layer): Tuyệt đối không bao giờ ghi đè dữ liệu đã bị che (098****567) ngược trở lại vào Database, vì chúng ta vẫn cần số điện thoại thật để hệ thống gửi SMS OTP hoặc gọi điện giao hàng. Việc che thông tin chỉ diễn ra ở bước trả dữ liệu ra UI hoặc Log.
  • Phân quyền rõ ràng (Role-based Masking): Đối với tài khoản có quyền Quản trị viên cấp cao (Admin), hệ thống có thể cho phép xem toàn bộ số điện thoại thật. Nhưng đối với nhân viên chăm sóc khách hàng thông thường hoặc hiển thị công cộng trên web, bắt buộc phải áp dụng Data Masking.

Lời kết

Kỹ thuật che thông tin khách hàng (Data Masking) không chỉ giúp sản phẩm của bạn tuân thủ các tiêu chuẩn bảo mật quốc tế mà còn nâng cao uy tín của doanh nghiệp trong mắt người dùng. Hãy đưa lớp bảo vệ này vào quy chuẩn thiết kế API ngay từ những dòng code đầu tiên!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.