Tools

Bảo mật chuỗi cung ứng Rust: cargo-audit, cargo-deny và cargo-vet

Tóm tắt

Tháng 9/2025 crates.io gỡ hai crate độc hại đánh cắp khoá ví crypto. cargo-audit bắt lỗ hổng đã biết, cargo-deny ép chính sách trong CI, cargo-vet đảm bảo mỗi dependency đã có người đáng tin đọc qua.

Rust chặn lỗi bộ nhớ trong code của bạn, nhưng không chặn được một crate độc hại bạn tự tay thêm vào Cargo.toml. Tháng 9/2025, đội crates.io gỡ hai crate faster_log và async_println. Cả hai giả làm thư viện log; khi chạy hoặc chạy test project dùng chúng, mã độc quét file log tìm khoá Ethereum, Solana rồi gửi ra ngoài. Tổng cộng khoảng 8.400 lượt tải trước khi bị phát hiện. An toàn bộ nhớ là một chuyện; an toàn chuỗi cung ứng là chuyện khác, và cần công cụ riêng.

Vì sao dependency Rust là bề mặt tấn công?

  • Cây phụ thuộc sâu: một project vài dependency trực tiếp thường kéo theo hàng trăm crate gián tiếp.
  • Code chạy lúc build: build.rs và procedural macro chạy ngay trên máy dev và CI khi biên dịch, trước cả khi bạn chạy chương trình.
  • Typosquatting: tên crate gần giống crate phổ biến để bẫy người gõ nhầm.
  • Lỗ hổng thật trong crate hợp pháp: kể cả code tốt cũng có CVE, đặc biệt trong khối unsafe.

Bộ công cụ: mỗi công cụ một việc

Công cụTrả lời câu hỏiLệnh cơ bản
cargo-auditCó crate nào trong Cargo.lock dính advisory đã biết?cargo install cargo-audit rồi cargo audit
cargo-denyCó vi phạm chính sách: lỗ hổng, license cấm, nguồn tải lạ, nhiều phiên bản trùng?cargo deny init rồi cargo deny check
cargo-vetMỗi dependency đã được ai đáng tin đọc và duyệt chưa?cargo vet init rồi cargo vet
cargo-auditableBinary đang chạy ở production chứa phiên bản crate nào?Nhúng cây dependency vào file thực thi để audit sau

RustSec: nguồn dữ liệu chung

cargo-audit và cargo-deny đọc RustSec Advisory Database, do Rust Secure Code Working Group duy trì. Dữ liệu được xuất theo thời gian thực sang OSV và được GitHub Advisory Database lẫn Debian dùng lại. Mỗi phát hiện ghi rõ crate, phiên bản, mã advisory, cách sửa (thường là nâng phiên bản) và đường đi trong cây phụ thuộc, nên bạn biết crate lỗi bị kéo vào từ đâu.

cargo-vet: từ "không có CVE" đến "đã có người đọc"

cargo-audit chỉ bắt được lỗ hổng đã được báo cáo. Crate độc hại mới toanh sẽ lọt qua. cargo-vet do Mozilla phát triển giải quyết đúng chỗ này: yêu cầu mỗi dependency phải có bản audit từ đội bạn hoặc tổ chức bạn tin. Để giảm khối lượng, nó cho phép:

  • Chia sẻ audit: nhập kết quả audit của các tổ chức khác dùng cùng crate.
  • Audit tương đối: chỉ đọc phần diff giữa hai phiên bản; nếu bản cũ đã duyệt thì bản mới cũng được duyệt.
  • Audit hoãn lại: đưa dependency chưa duyệt vào danh sách miễn trừ và thu hẹp dần theo thời gian, để áp dụng được ngay với project cũ.

Rủi ro và lưu ý

  • Không công cụ nào đủ một mình: audit bắt lỗ hổng đã biết; vet bắt code chưa ai đọc; cả hai không thay được việc hạn chế số dependency.
  • Cảnh báo bị bỏ qua: nếu CI chỉ in cảnh báo mà không làm fail build, sau vài tuần sẽ không ai đọc nữa.
  • Audit tốn công: cargo-vet đòi hỏi con người thật sự đọc code; hãy bắt đầu bằng danh sách miễn trừ và audit dependency mới trước.
  • Lock file: không commit Cargo.lock cho ứng dụng thì mỗi lần build có thể kéo phiên bản khác, kể cả phiên bản vừa bị đầu độc.

Áp dụng thế nào?

  • Dev: Trước khi thêm crate, kiểm tra tên chính xác, số lượt tải, người duy trì và repo nguồn. Chạy cargo audit trên máy trước khi mở PR.
  • Tech Lead: Đưa cargo deny check vào CI ở chế độ fail build, thêm job cargo audit chạy theo lịch (có GitHub Action sẵn) để bắt advisory mới cả khi không ai sửa code. Với sản phẩm nhạy cảm, bật cargo-vet cho dependency mới.
  • PM: Chuyển sang Rust giảm lỗi bộ nhớ nhưng không giảm rủi ro chuỗi cung ứng. Đưa chi phí audit dependency vào kế hoạch, giống như chi phí review code.

Nguồn & tham khảo

  1. crates.io: Malicious crates faster_log and async_println — Rust Blog
  2. RustSec Advisory Database — Rust Secure Code Working Group
  3. cargo vet — Mozilla