0

Thực chiến Device Authentication Bài 4: Zero Trust với mTLS (Mutual TLS): Chặn đứng hacker ngay từ tầng giao vận TCP/IP.

Sau khi thiết lập lớp phòng thủ bằng chữ ký điện tử (Digital Signature) ở Bài 3, hệ thống API của chúng ta đã có khả năng nhận diện thiết bị chính chủ và chống được đòn tấn công nhai lại.

Tuy nhiên, có một rủi ro lớn hơn: Backend của bạn vẫn "đứng trần" trên Internet. Bất kỳ ai cũng có thể dò ra địa chỉ IP của server và gửi hàng triệu request rác (chưa có chữ ký hợp lệ) vào hệ thống. Dù Middleware có chặn lại, việc phân tích header và băm mã RSA vẫn tiêu tốn CPU/RAM, dễ dàng dẫn đến sập server vì DDoS (Denial of Service).

Đây là lúc kiến trúc Zero Trust và mTLS (Mutual TLS) ra tay cứu giá. Chúng ta sẽ chặn đứng hacker ngay tại vòng bắt tay mạng (TCP/IP Handshake) trước khi chúng kịp nhìn thấy mã nguồn ứng dụng.


1. TLS vs. mTLS: Điểm khác biệt sống còn

Khi bạn lướt web (ví dụ: vào trang viblo.asia có ổ khóa xanh HTTPS), đó là TLS (Transport Layer Security) 1 chiều:

  • Trình duyệt (Bạn): Yêu cầu Server chứng minh danh tính (thông qua chứng chỉ SSL từ Let's Encrypt, Cloudflare).
  • Server: Trình chứng chỉ ra. Trình duyệt tin tưởng và bắt đầu mã hóa dữ liệu.
  • Vấn đề: Server không hề biết ai đang kết nối với nó. Nó mở cửa cho tất cả mọi người.

mTLS (Mutual TLS) - Xác thực 2 chiều:

  • Thiết bị: Yêu cầu Server chứng minh danh tính.
  • Server: CŨNG YÊU CẦU Thiết bị phải trình ra chứng chỉ (Client Certificate).
  • Kết quả: Nếu thiết bị không có chứng chỉ do chính hệ thống của bạn cấp phát, Server (Nginx, HAProxy) sẽ dập kết nối mạng ngay lập tức. Kẻ tấn công không thể kết nối, không thể gửi HTTP Request, và Backend (Golang/Node.js) hoàn toàn không tốn một chút tài nguyên nào để xử lý.

2. Kiến trúc hệ thống mTLS

Chúng ta không bắt Backend (Golang) phải gánh việc kiểm tra mTLS. Chúng ta sẽ giao việc này cho "người gác cổng" (Reverse Proxy), thường là Nginx.

  1. Thiết lập Cục Quản lý Chứng chỉ Nội bộ (Internal CA): Bạn đóng vai trò như Let's Encrypt của riêng mình. Bạn tạo ra một khóa gốc (Root CA).
  2. Cấp phát chứng chỉ: Bạn dùng Root CA này cấp cho Nginx (Server Cert) và cấp cho từng thiết bị (Client Cert).
  3. Cấu hình Nginx: Cấu hình để Nginx chỉ chấp nhận những kết nối có chìa khóa do đúng Root CA của bạn đúc ra.
  4. Backend "ẩn dật": Golang Backend chỉ lắng nghe kết nối từ localhost hoặc mạng nội bộ (VPC) từ Nginx đẩy vào.

3. Thực hành: Trở thành một CA (Certificate Authority)

Chúng ta sẽ dùng OpenSSL (có sẵn trên Linux/Mac) để sinh key.

Bước 1: Tạo Root CA (Khóa gốc)

# Sinh Private Key cho Root CA
openssl genrsa -out rootCA.key 4096

# Ký tự chứng nhận để tạo thành Root CA Certificate
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt
# (Nhập các thông tin như Country, Org... khi được hỏi)

Lưu ý: File rootCA.key là mạng sống của hệ thống. Phải cất giữ offline trong két sắt hoặc AWS KMS. File rootCA.crt thì công khai.

Bước 2: Tạo chứng chỉ cho Thiết bị (Client Certificate)

Giả sử lắp đặt máy bán vé số 01 (AFC-GATE-01).

# 1. Tạo Private Key nằm trên thiết bị
openssl genrsa -out device01.key 2048

# 2. Tạo File yêu cầu cấp chứng chỉ (CSR)
openssl req -new -key device01.key -out device01.csr -subj "/CN=AFC-GATE-01/O=MyMetroSystem"

# 3. Dùng Root CA để ký và cấp Certificate (.crt) cho thiết bị, hạn 1 năm
openssl x509 -req -in device01.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out device01.crt -days 365 -sha256

Đến đây, bạn copy 2 file device01.key và device01.crt nhét vào trong con chip của thiết bị phần cứng.


4. Cấu hình Nginx làm "Người Gác Cổng"

Nginx cần biết 2 thứ: Chứng chỉ của nó (để kết nối HTTPS thông thường) và Root CA (để soi chứng chỉ của thiết bị gửi lên).

Mở file nginx.conf và thêm cấu hình:

server {
    listen 443 ssl;
    server_name api.my-metro-system.com;

    # 1. SSL thông thường cho Server (Có thể dùng Let's Encrypt hoặc tự cấp)
    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;

    # 2. BẬT mTLS BẰNG CÁCH CHỈ ĐỊNH ROOT CA
    ssl_client_certificate /etc/nginx/certs/rootCA.crt;
    
    # Ép buộc phải có Client Cert (thất bại sẽ trả mã lỗi 400 Bad Request)
    ssl_verify_client on;
    # Bắt buộc chuỗi chứng chỉ phải nối thẳng đến Root CA của chúng ta
    ssl_verify_depth 2;

    location /api/v1/device/ {
        # Nếu thiết bị qua ải mTLS, chuyển request tới Golang Backend
        proxy_pass http://127.0.0.1:8080;
        
        # (Tùy chọn) Truyền tên thiết bị trích xuất từ Certificate cho Backend biết
        proxy_set_header X-Device-Cert-CN $ssl_client_s_dn;
    }
}

Điều kỳ diệu xảy ra:

  • Nếu hacker dùng Postman/Curl bắn request vào https://api.my-metro-system.com: Nginx ngắt kết nối ngay tức thì (Lỗi TCP/SSL Handshake). Hacker không thể chạm tới API Golang bên trong.
  • Nếu hacker kiếm một Client Cert từ hãng khác (không do rootCA.crt của bạn cấp): Nginx từ chối.
  • Chỉ khi request có chứa device01.crt hợp lệ, Nginx mới cho phép đi qua cổng.

5. Thiết bị gọi API như thế nào?

Khi viết firmware cho thiết bị (C++, Python hoặc Node.js nhúng), lúc gọi HTTP Request, bạn phải gắn thêm Client Certificate vào thư viện HTTP.

Ví dụ bằng cURL:

curl -X POST https://api.my-metro-system.com/api/v1/device/deduct-balance \
  --cert device01.crt \
  --key device01.key \
  -H "Content-Type: application/json" \
  -d '{"amount": 50000}'

Kết hợp mTLS và Chữ ký điện tử (Bài 3)

Bạn có thể thắc mắc: "Đã có mTLS siêu mạnh như thế này rồi, tôi có cần làm hàm kiểm tra Chữ ký điện tử ở Bài 3 nữa không?"

Câu trả lời là CÓ. Phải kết hợp cả hai.

  • mTLS bảo vệ tầng mạng, chống DDoS và ngăn chặn kẻ lạ tiếp cận API. Nhưng nó không kiểm soát được nội dung bên trong (Payload). Nếu hacker đánh cắp được thiết bị thật (cầm theo cả Cert), họ có thể Replay Attack.
  • Chữ ký (Digital Signature + Nonce) ở tầng ứng dụng đảm bảo tính nguyên vẹn của từng giao dịch (Transaction) và chống Replay Attack.

Hai lớp khiên này kết hợp tạo thành cấu trúc bảo mật vững như pháo đài (Defense in Depth).


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí