Khắc phục lỗi '400 Bad Request: No required SSL certificate was sent' trong mTLS

intermediate🔒 SSL/TLS2026-04-29| Linux (Ubuntu/CentOS), Nginx, Apache, Kubernetes Ingress-Nginx

Error Message

400 Bad Request: No required SSL certificate was sent
#mtls#nginx#client-certificate#xác-thực#ssl

Vấn đề

Ít thứ gì có thể chặn một lần triển khai nhanh hơn một lỗi mTLS khó hiểu. Bạn có thể đang thiết lập một API bảo mật hoặc một bảng điều khiển admin nội bộ thì trình duyệt đột nhiên gặp bế tắc. Thay vì ứng dụng của bạn, màn hình hiển thị một trang trắng trơn với một dòng chữ duy nhất:

400 Bad Request: No required SSL certificate was sent

Lỗi này là cách máy chủ nói rằng nó đang chờ một thẻ ID kỹ thuật số từ bạn nhưng không nhận được gì. Máy chủ của bạn được cấu hình để yêu cầu chứng chỉ phía client, nhưng quá trình bắt tay đã thất bại trước khi đến được logic ứng dụng của bạn.

Phân tích nguyên nhân gốc rễ

HTTPS tiêu chuẩn là một chiều: máy chủ chứng minh danh tính của nó với bạn. Mutual TLS (mTLS) biến điều này thành hai chiều. Ở đây, cấu hình máy chủ—thường là Nginx hoặc Apache—được đặt thành ssl_verify_client on;. Nếu trình duyệt, script hoặc ứng dụng di động của bạn không xuất trình chứng chỉ hợp lệ, máy chủ sẽ ngắt kết nối ngay lập tức.

Hầu hết các lỗi xuất phát từ một vài nguyên nhân cụ thể:

  • Chứng chỉ client chưa được cài đặt trong kho lưu trữ cục bộ của trình duyệt.
  • Chứng chỉ đã hết hạn tối qua hoặc chưa đến ngày 'Not Before'.
  • File ca.crt của máy chủ không nhận ra tổ chức phát hành đã ký chứng chỉ client của bạn.
  • Các công cụ tự động như cURL hoặc Postman chưa được trỏ đến các file .crt.key của bạn.

Bước 1: Kiểm tra cấu hình phía máy chủ

Bắt đầu bằng cách xác minh rằng Nginx biết Certificate Authority (CA) nào cần tin tưởng. Mở file cấu hình site của bạn, thường nằm tại /etc/nginx/sites-available/default:

server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;

    # The mTLS essentials
    ssl_client_certificate /etc/nginx/certs/ca.crt;
    ssl_verify_client on;

    location / {
        proxy_pass http://localhost:3000;
    }
}

Kiểm tra kỹ đường dẫn ssl_client_certificate. File này phải chứa CA gốc (và các intermediate nếu có) đã ký chứng chỉ người dùng của bạn. Nếu bạn cập nhật CA gần đây nhưng không làm mới file này, mọi request sẽ thất bại với lỗi 400.

Bước 2: Kiểm tra bằng cURL

Cô lập vấn đề bằng cách loại bỏ trình duyệt. Sử dụng curl giúp loại bỏ các vấn đề về cache và cài đặt UI ẩn. Bạn cần chuẩn bị sẵn các file client.crtclient.key trong terminal.

curl -v --cert client.crt --key client.key https://api.example.com

Nếu nhận được 200 OK nghĩa là máy chủ hoạt động bình thường. Vấn đề có thể nằm ở việc import chứng chỉ vào trình duyệt. Nếu vẫn trả về 400, chứng chỉ của bạn có thể chưa được ký bởi CA được định nghĩa trong cấu hình Nginx. Kiểm tra nhanh tổ chức phát hành:

openssl x509 -in client.crt -text -noout | grep Issuer

Kết quả đầu ra phải khớp với Common Name (CN) của chứng chỉ nằm tại đường dẫn ssl_client_certificate trên máy chủ của bạn.

Bước 3: Chuẩn bị chứng chỉ cho trình duyệt

Các trình duyệt như Chrome và Safari không chấp nhận các cặp .crt.key thô. Bạn cần đóng gói chúng thành một bundle PKCS#12 duy nhất (file .p12 hoặc .pfx) để hệ điều hành có thể xử lý chúng một cách an toàn.

Chạy lệnh này để tạo bundle:

openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -certfile ca.crt

Bạn sẽ được yêu cầu nhập mật khẩu xuất. Hãy chọn một mật khẩu mạnh; mật khẩu này bảo vệ khóa riêng tư của bạn khi nó nằm trong thư mục Downloads.

Mẹo hay: Khi tạo mật khẩu cho các bundle này, tôi sử dụng Password Generator trên ToolCraft. Công cụ này chạy hoàn toàn trong ngữ cảnh trình duyệt cục bộ của bạn, đảm bảo các tài sản bảo mật của bạn luôn được giữ riêng tư.

Sau khi có file client.p12, thực hiện các bước sau:

  • Vào Chrome Settings -> Privacy and Security -> Security.
  • Nhấp vào "Manage certificates" (thao tác này có thể mở Keychain hoặc Certificate Manager của hệ điều hành).
  • Import file client.p12 và nhập mật khẩu xuất.
  • Khởi động lại trình duyệt hoàn toàn. Khi bạn truy cập site, một hộp thoại sẽ xuất hiện yêu cầu bạn chọn chứng chỉ mới.

Bước 4: Khắc phục lỗ hổng trong chuỗi CA trung gian

Đôi khi CA gốc không phải là người ký trực tiếp. Nếu một CA trung gian đã cấp chứng chỉ của bạn, Nginx cần toàn bộ chuỗi xác minh. Chỉ cung cấp CA gốc sẽ khiến quá trình bắt tay thất bại vì máy chủ không thể "kết nối" khoảng tin tưởng.

Ghép chứng chỉ trung gian và gốc thành một bundle duy nhất:

cat intermediate.crt root.crt > full_ca_chain.crt

Cập nhật cấu hình Nginx để trỏ ssl_client_certificate đến file full_ca_chain.crt này rồi reload dịch vụ.

Kiểm tra và giám sát

Theo dõi log theo thời gian thực để xác nhận đã sửa xong. Một lần bắt tay mTLS thành công sẽ trông khác trong access log so với bắt tay thông thường.

tail -f /var/log/nginx/error.log /var/log/nginx/access.log

Để debug sâu hơn, thêm $ssl_client_verify vào định dạng log Nginx của bạn. Nó sẽ ghi rõ "SUCCESS", "NONE", hoặc "FAILED:subject-mismatch," cho bạn biết chính xác lý do tại sao một lần bắt tay thất bại.

Phòng ngừa

Tránh các sự cố lúc 3 giờ sáng với những phương pháp sau:

  • Tự động hóa vòng đời: Sử dụng cert-manager trong Kubernetes hoặc HashiCorp Vault để xoay vòng chứng chỉ trước khi hết hạn.
  • Cảnh báo hết hạn: Thiết lập giám sát để thông báo cho bạn 30, 15 và 7 ngày trước khi CA hoặc chứng chỉ client hết hạn.
  • Tài liệu hướng dẫn: Tạo một hướng dẫn nội bộ đơn giản cho các thành viên trong nhóm. Giao diện chứng chỉ của trình duyệt thường rất khó dùng và thường yêu cầu khởi động lại hoàn toàn để nhận ra các thay đổi mới.

Related Error Notes