Khi mã nguồn của bạn sạch, nhưng thư viện đi kèm thì không
Khoảng 2 năm trước, mình làm dự án Fintech cho một ngân hàng lớn. Cả team cực kỳ tự tin vì code coverage đạt trên 90%, pass mọi đợt Unit Test và Code Review. Thế nhưng, ngay trước ngày release, bộ phận Security gửi về một bản báo cáo “đỏ lòm” với hơn 40 lỗ hổng nghiêm trọng (Critical).
Oái oăm ở chỗ, không có lỗi nào nằm ở code tụi mình viết. Tất cả đều ẩn sâu trong các thư viện mã nguồn mở. Có những package là “dependency của dependency” (transitive dependencies) mà anh em trong team còn chẳng biết nó tồn tại.
Một ví dụ điển hình là lỗ hổng Log4j kinh điển; dù bạn không dùng trực tiếp, nhưng một thư viện logging khác lại kéo nó vào. Lúc đó, team mình phải thức trắng 48 giờ để rà soát và nâng cấp. Bài học rút ra rất rõ ràng: Kiểm soát mã nguồn thôi là chưa đủ, bạn phải kiểm soát cả chuỗi cung ứng phần mềm (Software Supply Chain).
Tại sao chúng ta thường bỏ quên các thư viện mã nguồn mở?
Trong các dự án hiện đại, có đến 80% mã nguồn thực tế là “đi mượn” từ các package bên thứ ba. Chỉ với một dòng lệnh npm install hoặc pip install, bạn đã đưa hàng nghìn dòng code lạ vào hệ thống của mình.
Rủi ro thường đến từ ba phía:
- Sự chủ quan: Tin tưởng tuyệt đối vào các thư viện có hàng triệu lượt tải.
- Dependencies bắc cầu: Bạn cài thư viện A, A kéo theo B, B lại chứa lỗ hổng ở C.
- Nợ bảo mật (Security Debt): Ngại cập nhật vì sợ break hệ thống, dẫn đến việc dùng các phiên bản đã lỗi thời từ 3-4 năm trước.
Tra cứu thủ công trên trang CVE là nhiệm vụ bất khả thi khi số lượng thư viện lên tới hàng trăm. Đó là lúc OWASP Dependency-Check trở thành trợ thủ đắc lực.
So sánh các giải pháp SCA phổ biến
Trước khi chốt phương án, mình đã cân nhắc khá kỹ các ứng viên:
- Snyk: Giao diện cực ngon, báo cáo chi tiết. Tuy nhiên, bản free chỉ cho phép quét giới hạn (khoảng 200 lần/tháng), không phù hợp với các team chạy CI/CD liên tục.
- GitHub Dependabot: Tiện vì có sẵn, nhưng chỉ quét được code trên GitHub. Nếu bạn dùng GitLab Self-managed hay Bitbucket thì chịu.
- NPM Audit: Nhanh nhưng chỉ giới hạn trong hệ sinh thái Node.js.
OWASP Dependency-Check thắng thế vì nó hoàn toàn miễn phí, thuộc dự án SCA (Software Composition Analysis) uy tín. Nó quét dựa trên cơ sở dữ liệu NVD (National Vulnerability Database) và hỗ trợ đa ngôn ngữ từ Java, .NET đến Python, Node.js.
Triển khai thực tế cho các dự án
Dưới đây là cách mình cấu hình nhanh cho 3 môi trường phổ biến nhất.
1. Dự án Java (Maven)
Bạn chỉ cần khai báo plugin trong file pom.xml. Không cần cài đặt rườm rà vào hệ điều hành.
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>12.1.0</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
Chạy lệnh mvn verify để xem báo cáo HTML trong thư mục target.
2. Dự án Node.js & Python (Dùng Docker)
Thay vì cài Java để chạy Dependency-Check, mình thường dùng Docker cho gọn. Cách này giúp môi trường dev luôn sạch sẽ.
docker run --rm \
-e USER_ID=$(id -u) \
-v $(pwd):/src \
-v "$HOME/odc-data:/usr/share/dependency-check/data" \
owasp/dependency-check --project "MyProject" --scan /src
Tích hợp CI/CD: Chặn đứng lỗ hổng từ cửa ngõ
Đừng đợi đến lúc chuẩn bị release mới quét. Hãy biến nó thành một gatekeeper trong pipeline. Nếu phát hiện lỗi High (CVSS >= 7.0), pipeline phải fail ngay lập tức.
Lưu ý quan trọng: Hiện tại NVD đã giới hạn rate limit. Bạn bắt buộc phải đăng ký một NVD API Key (miễn phí) để việc quét không bị gián đoạn.
# Ví dụ GitHub Actions
- name: OWASP Dependency Check
uses: dependency-check/Dependency-Check-Action@main
with:
project: 'FintechApp'
path: '.'
format: 'HTML'
args: >
--failOnCVSS 7
--nvdApiKey ${{ secrets.NVD_API_KEY }}
Kinh nghiệm “xương máu” khi vận hành
Khi triển khai diện rộng cho team, mình rút ra 3 điểm mấu chốt:
- Tối ưu hóa Cache: Database của NVD nặng khoảng 250MB+. Nếu không cache thư mục data trong CI/CD, mỗi lần build bạn sẽ mất thêm 5-10 phút chỉ để tải dữ liệu.
- Xử lý False Positives: Công cụ đôi khi nhận diện nhầm (ví dụ thư viện nội bộ trùng tên với một package dính lỗi). Hãy dùng file
suppression.xmlđể loại bỏ các cảnh báo sai sau khi đã kiểm tra kỹ. - Ưu tiên xử lý: Đừng cố fix sạch 100% mọi lỗi Low/Medium nếu resources hạn hẹp. Hãy tập trung vào các lỗi có điểm CVSS từ 7.0 trở lên trước để đảm bảo an toàn cốt lõi.
Chủ động bảo mật chuỗi cung ứng là cách rẻ nhất để bảo vệ sản phẩm. Hy vọng bài viết giúp anh em tự tin hơn khi quản lý các thư viện trong dự án. Chúc anh em fix bug thuận lợi!

