Với chúng tôi, bảo mật không phải là một lớp thêm vào sau, mà là trung tâm của kiến trúc. Cô lập dữ liệu, tách biệt định danh và ghi idempotent được khắc vào tầng thấp nhất của mã — không phải một tùy chọn có thể tắt, mà là cách hệ thống vận hành.
Cô lập cấp dòng
Ghi idempotent
Truy vấn có tham số
Cô lập loopback
Cô lập dữ liệu
Cô lập cấp dòng — fail-closed
Trên mọi bảng thuộc phạm vi tenant, PostgreSQL Row-Level Security FORCE luôn được bật; chính sách ràng buộc từng dòng theo điều kiện "tenant_id = current_setting('app.current_tenant')".
Một truy vấn đến mà không thiết lập tenant context sẽ trả về không dòng nào — thậm chí không phải lỗi, mà lặng lẽ trống. Việc nhìn thấy dữ liệu của một phòng khám bằng phiên của một phòng khám khác là bất khả về mặt kiến trúc.
Kiểm thử cô lập chéo-tenant bắt buộc luôn xanh trong tích hợp liên tục (CI); nếu đỏ, mã không được hợp nhất.
Ghi nguyên tử (atomic)
Định danh transaction-local, giao dịch nguyên tử
Danh tính tenant được thiết lập ngay từ ĐẦU transaction trong mỗi thao tác ghi và chỉ có hiệu lực trong suốt transaction đó; nó không bám vào connection pool và không rò rỉ sang các yêu cầu khác.
Các giao dịch đa thực thể (hóa đơn + mục + thanh toán + trừ kho) là nguyên tử trong một transaction duy nhất: hoặc ghi tất cả cùng nhau hoặc không ghi gì. Không tạo ra bản ghi dở dang, thiếu nhất quán.
Quyền
Quyền theo vai trò (RBAC) được thực thi trên máy chủ
Kiểm soát quyền được thực hiện ở tầng API; không bao giờ tin vào máy khách hay giao diện trước. Việc ẩn một menu trên trình duyệt chỉ liên quan đến hiển thị — quyết định thật nằm ở máy chủ.
Các thao tác thay đổi ở lõi (Phase 1) được bảo vệ theo các vai trò admin, thư ký và bác sĩ. Ngay cả khi một vai trò không có thẩm quyền gọi endpoint, yêu cầu vẫn bị từ chối.
Chống lặp lại
Ghi idempotent — không giao dịch trùng
Mỗi yêu cầu ghi đều mang một Idempotency-Key; khóa phía máy chủ chặn giao dịch thứ hai đến với cùng một khóa.
Ngay cả khi mạng bị ngắt hoặc máy khách gửi lại cùng một yêu cầu, sẽ không có khoản thu hay hóa đơn thứ hai nào được tạo. Kết quả luôn duy nhất và có thể dự đoán.
Bảo mật truy vấn
SQL injection là bất khả — truy vấn có tham số
Mọi truy vấn cơ sở dữ liệu đều là các câu lệnh hoàn toàn có tham số, được sqlc tạo ra tại thời điểm biên dịch. Trong toàn bộ mã nguồn không có lấy một dòng nào tự dựng SQL bằng cách nối chuỗi thủ công với đầu vào của người dùng.
Điều này loại bỏ về mặt cấu trúc cả một lớp tấn công SQL injection — nó dựa vào cách câu truy vấn được xây dựng, chứ không phải vào nỗ lực "lọc" hay "thoát ký tự".
Bề mặt mạng
Cô lập loopback — lõi đóng với bên ngoài
API lõi chỉ lắng nghe trên 127.0.0.1 (loopback). Mọi nỗ lực gắn vào 0.0.0.0 hoặc một IP công khai đều bị từ chối ngay khi khởi động; lõi không bao giờ được mở ra Internet trong bất kỳ trường hợp nào.
Bề mặt công khai duy nhất là một cổng mỏng (BFF): nó không giữ nghiệp vụ ngoài phiên đăng nhập, render và CSRF. Trình duyệt không bao giờ có thể nhìn thấy hay định địa chỉ trực tiếp tới API lõi.
Định danh & phiên
Mật khẩu argon2id, khóa phiên opaque
Mật khẩu được hash bằng argon2id, một thuật toán chuẩn ngành và khó tấn công qua bộ nhớ; không dùng hash thô hay yếu.
Khóa phiên là các giá trị opaque ngẫu nhiên mật mã dài 32 byte, được lưu trong Redis và hết hạn theo TTL. Trình duyệt chỉ nhận được cookie HttpOnly + Secure + SameSite; khóa không bao giờ được để lộ ra JavaScript.
Kiểm toán
Nhật ký kiểm toán không thể thay đổi (chỉ ghi thêm)
Các thao tác quan trọng được ghi vào nhật ký kiểm toán chỉ-ghi-thêm trong CÙNG một transaction với thao tác thay đổi kích hoạt chúng. Nếu giao dịch bị hoàn tác thì nhật ký kiểm toán cũng không được ghi — hai điều này không thể tách rời.
Quyền UPDATE/DELETE trên bảng kiểm toán đã bị thu hồi; các bản ghi không thể chỉnh sửa hay xóa về sau. Lịch sử giữ nguyên như nó vốn có.
Privacy
Che dữ liệu nhạy cảm
TCKN, mật khẩu, khóa phiên và dữ liệu y tế không lọt vào nhật ký dưới bất kỳ hình thức nào. Ngay cả trong kết quả gỡ lỗi, các trường này cũng được che.
Khi cần, các trường nhạy cảm được mã hóa ở cấp cột. Dữ liệu y tế nhạy cảm được bảo vệ bằng các quy tắc được đặt vào ngay từ đầu trong thiết kế.
Toàn vẹn Tiền tệ
Bảo mật tiền tệ — numeric, bút toán đảo
Tiền được lưu ở mọi nơi bằng numeric(14,2); không tính toán tiền bằng float. Việc làm tròn diễn ra tại một điểm duy nhất, trên máy chủ — không xảy ra lệch xu hay sai số làm tròn.
Hủy và hoàn tiền được xử lý bằng một bút toán đảo thay vì xóa bản ghi. Số dư công nợ không được nhập thủ công; luôn được suy ra từ tổng hóa đơn và thanh toán. Lịch sử không bị phá vỡ.
Chuyển giao
Bảo mật truyền tải & trình duyệt
Toàn bộ lưu lượng được truyền qua HTTPS/TLS và HSTS được bật; trình duyệt chỉ thiết lập kết nối ở dạng mã hóa.
Chính sách bảo mật nội dung (CSP) nghiêm ngặt chặn inline script; X-Frame-Options DENY ngăn clickjacking, X-Content-Type-Options nosniff ngăn nhầm lẫn kiểu MIME. Referrer-Policy và Permissions-Policy cũng được áp dụng.
Quan trọng
Tách biệt tier danh tính + mặt phẳng quản trị riêng
Người dùng phòng khám, cổng thông tin bệnh nhân và nhà vận hành nền tảng là các tier danh tính RIÊNG BIỆT: tiêu đề riêng, không gian phiên riêng. Khóa của một tier không hoạt động ở tier khác — ranh giới quyền được tách bạch tuyệt đối.
Các điểm cuối nền tảng và quản trị (cấp phát tenant, lập hóa đơn, quản lý tự động hóa/tiện ích, tạo API key) KHÔNG NẰM trong public API.
Các chức năng này chạy trên một mặt phẳng điều khiển riêng biệt, nội bộ, có mẫu định danh khác (khóa quản trị chuyên biệt); không thể truy cập và không thể phát hiện từ bên ngoài. Nhờ đó, bề mặt tấn công giảm đi rõ rệt.
CÁCH HOẠT ĐỘNG
Một transaction, cô lập fail-closed
Luồng khái niệm dưới đây minh họa cách mỗi thao tác ghi được khóa vào tenant và giữ tính idempotent. Chỉ nhằm mục đích diễn giải.
# 1) Tenant context được thiết lập ngay từ ĐẦU transaction (chỉ riêng cho tx này)
BEGIN;
SELECT set_config('app.current_tenant', :session_tenant_id, true);
# 2) Khóa Idempotency-Key — cùng một khóa sẽ không tạo giao dịch thứ haiSELECT lock_idempotency(:idempotency_key);
# 3) Ghi đa thực thể — tất cả đều nguyên tử trong một tx duy nhấtINSERT INTO invoices ...; # RLS: tenant_id tự động bao gồmINSERT INTO payments ...;
INSERT INTO audit_log ...; # append-only, cùng một tx
COMMIT;
# Nếu context không được thiết lập, chính sách RLS sẽ không trả về dòng nào:SELECT * FROM patients; --> 0 dòng (không phải lỗi, lặng lẽ trống)
Có thể kiểm chứng độc lập
Một phần bảo mật truyền tải có thể quan sát được từ bên ngoài: bạn có thể tự kiểm tra chứng chỉ HTTPS/TLS của kết nối, cùng các tiêu đề bảo mật phản hồi như HSTS và chính sách bảo mật nội dung, ngay trong công cụ phát triển của trình duyệt. Các tuyên bố của chúng tôi dựa trên kiểm soát kiến trúc, không phải câu chữ tiếp thị.
Bạn có câu hỏi về kiến trúc bảo mật?
Đội ngũ của chúng tôi rất vui được trao đổi cùng bạn về các chi tiết kỹ thuật và yêu cầu tuân thủ của bạn.