Lọc PII trong error monitoring mà không mất ngữ cảnh
Mình chạy bộ lọc của Belvador trên 16 mẫu lỗi giả lập, sửa ba lỗ hổng là lỗi của chính mình rồi chạy lại. Secret có hình dạng quen thuộc đều bị xoá; số điện thoại và tên người vẫn lọt.
Andrew Babo7 phút đọc
Trong bài này

Bộ lọc tự động trong error monitoring giỏi đúng một việc: secret có hình dạng dễ nhận ra. API key, token, JWT, số thẻ và mật khẩu trong URL đều có mẫu để một luật bắt được. Dữ liệu cá nhân không có hình dạng cố định, như tên người hay số điện thoại trong nước, thì lọt qua, còn luật dựa trên tên key lại xoá cả thứ bạn muốn giữ.
Mình đo cả hai chuyện vào ngày 26/10/2026. Mình chạy chính bộ lọc trên node của Belvador, bật mọi luật, trên 16 mẫu giả lập, và ghi ra trước những gì một người cẩn thận muốn xoá. Ba chỗ bị sót là lỗi trong luật của chính mình, nên mình sửa rồi chạy lại đúng các mẫu đó với code đã phát hành thành node 0.1.30.
Vì sao cần bộ lọc#
Báo cáo lỗi cố tình gom ngữ cảnh, mà ngữ cảnh gồm mọi thứ đang nằm trong bộ nhớ lúc hỏng. Sentry chẳng hạn bật sẵn bộ lọc phía server: “Data scrubbing is enabled by default and we highly recommend you keep it that way.” Hướng dẫn của OpenTelemetry nói rõ giới hạn: một công cụ “can’t determine what data is sensitive in your specific context on its own”, tức tự nó không biết dữ liệu nào nhạy cảm trong bối cảnh của bạn.
Vậy là có hai việc. Bộ lọc chung xoá những thứ trông nguy hiểm ở mọi nơi. Code của bạn xoá những thứ nhạy cảm trong chính ứng dụng của bạn.
16 mẫu thử#

| Mẫu | Mong muốn | Lần đầu | Sau khi sửa (node 0.1.30) |
|---|---|---|---|
| Email trong message lỗi | xoá | xoá phần tên, giữ tên miền | như cũ |
| JWT trong message | xoá | đã xoá | như cũ |
Key sk_live_… trong message | xoá | đã xoá | như cũ |
| Số thẻ hợp lệ theo Luhn | xoá | đã xoá | như cũ |
| 16 chữ số không hợp lệ theo Luhn | giữ | đã giữ | như cũ |
?token= trong URL | xoá | đã xoá, giữ order=ORD-42 | như cũ |
email=linh%40example.test trong query | xoá | vẫn giữ: dấu @ bị mã hoá thành %40 | xoá phần tên |
Authorization: Basic … trong chữ | xoá | đã xoá | như cũ |
https://user:pass@host | xoá cả hai | xoá mật khẩu, giữ tên đăng nhập | xoá cả hai |
phone=0912345678 trong breadcrumb | xoá | vẫn giữ | vẫn giữ |
Tên người và số +84 trong một ghi chú | xoá | vẫn giữ | vẫn giữ |
| Địa chỉ IP nằm trong một câu | xoá | vẫn giữ | số cuối thành 0 |
| Địa chỉ IP là giá trị của một trường | che | số cuối thành 0: 192.0.2.0 | như cũ |
order_id, trace_id, status, retries | giữ | đã giữ | như cũ |
author, session_count, token_count | giữ | cả ba bị lọc | cả ba bị lọc |
password, api_key, session | xoá | đã xoá | như cũ |
Mười ba mẫu lẽ ra phải mất bớt dữ liệu. Ở lần đầu, bảy mẫu được làm sạch hoàn toàn và một mẫu được che đúng thiết kế; hai mẫu chỉ sạch một phần, ba mẫu bị bỏ sót. Sau khi sửa, chín mẫu sạch hoàn toàn, hai mẫu được che, và chỉ hai mẫu có số điện thoại là còn lọt. Cả hai mẫu cần giữ đều được giữ ở cả hai lần, và vẫn là ba key vô hại đó bị lọc mất.
Những chỗ bị sót có điểm chung#

Những chỗ bị sót không có hình dạng nào để một luật chung dựa vào.
- Số điện thoại có rất nhiều cách viết. Một luật đủ rộng để bắt cả
0912345678lẫn+84 912 345 678sẽ ăn luôn mã đơn hàng, mốc thời gian và ID. - Tên người chỉ là chữ. Không mẫu nào phân biệt được “Nguyễn Văn An” với tên một sản phẩm.
- Email bị mã hoá có đúng hình dạng, nhưng chỉ sau khi giải mã. Lần đầu, bộ lọc so với chữ thô.
- IP trong câu bị bỏ qua vì lần đầu bộ lọc chỉ che IP khi cả giá trị là một địa chỉ IP.
Email bị mã hoá, tên đăng nhập trong URL và IP trong câu là lỗ hổng trong luật của chính mình, và node 0.1.30 đã vá (SDK 0.4.1 vá luôn phần email và IP): bộ lọc giờ đọc %40 như @, bỏ cả phần user:pass@ trong URL, và đổi số cuối của địa chỉ IPv4 public trong câu thành 0. Địa chỉ nội bộ như 10.0.3.17 vẫn giữ nguyên, vì chúng giúp debug mà không chỉ ra ai cả. Tên người và số điện thoại thì lúc nào cũng cần code của bạn giúp.
Vì sao key vô hại biến mất#
Luật theo tên key hoạt động kiểu “có chứa”: key nào có auth, session hay token trong tên đều bị lọc. Nhờ vậy nó bắt được user_auth_header và sessionToken, đúng như bạn muốn. Nhưng nó cũng bắt luôn author, session_count và token_count, thứ bạn không hề muốn.
Đánh đổi này là có chủ ý: bộ lọc để lọt một secret thì tệ hơn bộ lọc giấu mất một con số đếm. Nếu một trường quan trọng cho việc debug, hãy đổi tên nó, ví dụ llm_tokens_used thành llm_usage_units, hoặc giữ nó trong một tag mà team đã kiểm tra.
Nên tự thêm gì trong code#
SDK báo lỗi có một hook chạy trước khi gửi bất cứ thứ gì. Tài liệu của Sentry mô tả beforeSend là hook “can be used, for instance, for manual PII stripping before sending”, tức dùng được để tự xoá PII trước khi gửi. Hãy dùng nó cho những thứ chỉ ứng dụng của bạn biết:
- Thay object user bằng một ID nội bộ. Đừng bao giờ gửi email hay tên làm thông tin user.
- Xoá các trường chữ tự do bạn thu thập: ghi chú, địa chỉ, tin nhắn, từ khoá tìm kiếm.
- Chuẩn hoá số điện thoại theo định dạng của bạn rồi che đi.
- Giải mã query string trước khi chạy các kiểm tra của riêng bạn.
- Giữ lại những gì giúp debug mà không phải dữ liệu cá nhân: mã đơn, trace ID, mã trạng thái, số lần thử lại, feature flag.
Chỉ thử bằng giá trị giả. Danh sách những thứ không bao giờ được ghi log của OWASP mở đầu bằng “Authentication passwords Database connection strings Encryption keys”; một bài test dùng giá trị thật là đã làm lộ nó rồi.
Belvador giúp ở đâu#
Belvador lọc hai lần: SDK làm sạch event trước khi rời ứng dụng, ngay sau khi beforeSend của bạn chạy, rồi node của bạn lọc lại bằng bộ luật viết riêng trước khi lưu bất cứ thứ gì. Trang bảo vệ dữ liệu liệt kê mọi luật và những trường hợp không bộ lọc nào đảm bảo được, còn trang cấu hình SDK chỉ chỗ đặt beforeSend. Event đã lọc được lưu trên một node trong chính dự án Hetzner của bạn, như trang BYOC trên Hetzner giải thích, còn trang bảo mật nói về các biện pháp kiểm soát còn lại của Belvador.
Đọc tiếp#
Thuộc bài hướng dẫn: Gửi lỗi production cho LLM thế nào cho an toàn
Bài liên quan
Mọi bài viết
Hướng dẫn
Gửi lỗi production cho LLM thế nào cho an toàn
Một event lỗi chứa secret, dữ liệu cá nhân và chữ người dùng gõ vào. Mình gửi một event có lệnh ẩn cho bốn model 72 lần; dán nguyên văn, một model làm theo cả sáu lần và có lần khuyên tắt xác thực.
Andrew Babo8 phút đọc

Hướng dẫn
Lưu trữ dữ liệu lỗi và nơi nhà cung cấp AI xử lý: hai lựa chọn riêng
Giữ dữ liệu lỗi ở EU không nói gì về nơi một model AI xử lý cái lỗi bạn dán vào. Mình so cài đặt của bốn nhà cung cấp AI và thấy nơi lưu và nơi xử lý là hai nút vặn khác nhau.
Andrew Babo6 phút đọc
Đọc tiếp trong tài liệu
Xem lỗi production của chính bạn như thế này
Belvador chạy trên máy chủ Hetzner của chính bạn: lỗi, cron, uptime và trace — dữ liệu vẫn là của bạn.