Hướng dẫn sử dụng Snyk để quét lỗ hổng bảo mật trong mã nguồn và thư viện (SCA) cho dự án Node.js và Python

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Mình từng bị brute-force SSH lúc nửa đêm — kể từ đó, mình luôn setup bảo mật ngay từ đầu dự án, không chờ đến lúc ra production mới nghĩ đến. Một trong những thứ hay bị bỏ qua nhất chính là lỗ hổng trong thư viện bên thứ ba — cái mà mình vô tư npm install hay pip install mà không kiểm tra gì cả.

Đây là chỗ Snyk vào cuộc. Công cụ SCA (Software Composition Analysis) này đọc package.json, requirements.txt, Pipfile… rồi so khớp với database CVE của mình để tìm lỗ hổng đã biết và gợi ý phiên bản vá. Snyk Vulnerability DB thường cập nhật CVE sớm hơn NVD vài ngày đến vài tuần — đôi khi quan trọng khi exploit đang được khai thác ngoài thực tế. Và nó tích hợp thẳng vào CI/CD, không cần làm gì thủ công.

Chạy thử ngay trong 5 phút

Không cần tài khoản để bắt đầu. Cài Snyk CLI và quét thử dự án hiện tại:

# Cài global qua npm
npm install -g snyk

# Hoặc dùng npx nếu không muốn cài global
npx snyk --version

Sau đó chạy ngay trong thư mục dự án:

# Với Node.js
cd my-node-project
snyk test

# Với Python
cd my-python-project
snyk test --file=requirements.txt

Lần đầu chạy sẽ yêu cầu xác thực:

snyk auth

Browser tự mở để đăng nhập. Free plan cho phép quét không giới hạn với open source projects. Auth xong, chạy lại snyk test và bạn thấy ngay:

Testing /home/user/my-node-project...

Found 3 vulnerabilities in 2 paths

  ✗ High severity vulnerability found in lodash
    Description: Prototype Pollution
    Info: https://snyk.io/vuln/SNYK-JS-LODASH-567746
    Introduced through: [email protected]
    Fix: upgrade to [email protected]

  ✗ Medium severity vulnerability found in axios
    ...

Snyk hoạt động như thế nào?

Snyk không phải SAST — nó không đọc logic code của bạn. Thay vào đó, nó đọc lock file hoặc manifest file, dựng lại toàn bộ dependency tree bao gồm cả transitive dependencies, rồi so khớp từng package với database CVE.

File nào được hỗ trợ?

  • Node.js: package.json, package-lock.json, yarn.lock
  • Python: requirements.txt, Pipfile, Pipfile.lock, pyproject.toml, poetry.lock
  • Khác: Go modules, Maven, Gradle, Composer, Ruby Gems, .NET…

Với Python, mình thường dùng Pipfile.lock thay vì requirements.txt — Snyk thấy được dependency tree đầy đủ hơn, kể cả các gói bị kéo vào gián tiếp:

# Quét với Pipfile.lock (chính xác hơn)
snyk test --file=Pipfile.lock

# Hoặc để Snyk tự detect
snyk test

Đọc kết quả quét

Mỗi lỗ hổng Snyk báo sẽ có:

  • Severity: Critical / High / Medium / Low
  • CVE ID và link chi tiết
  • Introduced through: gói nào kéo lỗ hổng này vào
  • Fix: upgrade lên phiên bản nào để vá

Phần Introduced through là thứ mình thấy đắc dụng nhất. Hồi dự án cũ, mình mất gần tiếng mới tìm ra [email protected] bị kéo vào qua chuỗi webpackloader-utilslodash. Snyk trace ra ngay trong vài giây, kèm gợi ý upgrade luôn.

Tích hợp vào CI/CD

Chạy tay OK cho việc debug nhanh. Nhưng giá trị thực của Snyk nằm ở chỗ khác — gắn vào pipeline để mọi PR đều được quét tự động, không cần ai nhớ.

GitHub Actions

# .github/workflows/security.yml
name: Snyk Security Scan

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Run Snyk to check for vulnerabilities
        uses: snyk/actions/node@master   # hoặc python@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

Thêm SNYK_TOKEN vào GitHub Secrets (lấy từ snyk auth hoặc Snyk dashboard). Option --severity-threshold=high quan trọng — không set thì pipeline fail vì hàng chục lỗi Low/Medium chưa có fix, và team sẽ tắt cái check này trong vòng một tuần.

GitLab CI

# .gitlab-ci.yml
snyk_scan:
  image: node:18
  stage: test
  script:
    - npm install -g snyk
    - snyk auth $SNYK_TOKEN
    - snyk test --severity-threshold=high
  allow_failure: false
  only:
    - merge_requests
    - main

Python project trong CI

# GitHub Actions cho Python
- name: Set up Python
  uses: actions/setup-python@v4
  with:
    python-version: '3.11'

- name: Install dependencies
  run: pip install -r requirements.txt

- name: Run Snyk
  uses: snyk/actions/python@master
  env:
    SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
  with:
    args: --file=requirements.txt --severity-threshold=high

Nâng cao: snyk monitor và cảnh báo liên tục

snyk test chỉ quét tại thời điểm chạy. snyk monitor thì khác — nó lưu snapshot dependency tree lên Snyk cloud và theo dõi liên tục. CVE mới xuất hiện sau khi bạn deploy? Snyk tự alert qua email hoặc Slack, không cần chạy lại gì cả.

# Chạy sau khi deploy hoặc sau CI/CD thành công
snyk monitor --project-name="my-app-production"

Trong pipeline của mình: snyk test chạy ở bước kiểm tra PR để block merge khi có lỗi mới, còn snyk monitor chạy ở bước cuối deploy-to-production để giám sát sau khi đã lên. Hai lệnh bổ sung nhau — không thay thế nhau.

Fix tự động với snyk fix

# Thử fix tự động (chỉ upgrade minor/patch)
snyk fix

# Xem diff trước khi apply
snyk fix --dry-run

Với Node.js, tính năng này khá ổn — Snyk tự sửa package.json và chạy npm install để update lên phiên bản an toàn nhất mà vẫn tương thích. Với Python thì còn experimental, dùng thận trọng hơn.

Ignore lỗ hổng có chủ đích

Đôi khi CVE không áp dụng cho use case của bạn — ví dụ, lỗ hổng liên quan đến một feature bạn hoàn toàn không dùng. Thay vì để pipeline fail mãi:

# Ignore một lỗ hổng cụ thể trong 30 ngày
snyk ignore --id=SNYK-JS-LODASH-567746 --reason="Not exploitable in our use case" --expiry=2026-05-01

Lệnh này tạo ra file .snyk trong project. Commit file này vào git — để sau 3 tháng khi có người hỏi “sao cái CVE này được ignore?”, họ đọc được lý do thay vì phải đào lịch sử Slack.

Tips thực tế từ dự án thực

1. Đừng để Snyk chặn toàn bộ từ đầu. Codebase cũ thường có vài chục đến vài trăm lỗ hổng — cắm Snyk vào và để pipeline fail ngay là cách nhanh nhất để team ghét tool này. Bắt đầu với --severity-threshold=critical, sau vài sprint hạ xuống high, rồi mới tiến tới medium.

2. Kết hợp với npm audit / pip-audit. Mỗi tool có database riêng — đôi khi một cái bắt được cái kia không. Với Python, mình hay chạy cả hai:

# pip-audit — tool của PyPA, database từ PyPI Advisory
pip install pip-audit
pip-audit -r requirements.txt

# So sánh với Snyk
snyk test --file=requirements.txt

3. Quét cả Docker image. OS packages bên trong container cũng là attack surface, và hay bị bỏ qua hơn cả dependencies. Snyk quét được luôn:

# Quét image đã build
snyk container test my-app:latest

# Hoặc quét image từ registry trước khi dùng
snyk container test python:3.11-slim

Mình hay chạy cái này trước khi chọn base image. python:3.11-slim thường ít lỗ hổng OS hơn python:3.11 mấy chục cái vì ít package pre-installed hơn — đáng để check trước khi commit vào Dockerfile.

4. Free plan đủ dùng cho nhóm nhỏ. Snyk free cho phép quét không giới hạn open source projects và 200 test/tháng cho private repos. Với team nhỏ hoặc side project thì ổn. Paid plan chủ yếu thêm SAST, license compliance, và quản lý nhiều team.

5. Tạo baseline ngay hôm nay. Chưa tích hợp CI/CD cũng không sao — chạy snyk monitor một lần trên production codebase là xong. Snyk sẽ alert khi có CVE mới xuất hiện, không cần làm gì thêm.

Firewall, SSH key, 2FA — những thứ này mọi người nhớ. Dependencies thì không. Nhưng đây lại là điểm vào của phần lớn các cuộc tấn công chuỗi cung ứng gần đây. Mình setup Snyk mất khoảng 10 phút. Bỏ qua thì rủi ro khó đong đếm hơn nhiều.

Share: