Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Security Testing Automation — DAST & SAST

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn là QA của một fintech ở TP.HCM. Đội dev vừa merge một tính năng thanh toán mới, test chức năng chạy xanh 100%, PM hài lòng, sản phẩm lên production tối thứ Sáu. Đến sáng thứ Hai, một researcher gửi email báo rằng endpoint /api/user/{id} trả về thông tin của bất kỳ user nào chỉ cần đổi số ID trên URL. Đó là lỗ hổng IDOR (Insecure Direct Object Reference) — và không một test case chức năng nào của bạn bắt được nó, vì về mặt chức năng thì API hoạt động "đúng".

Đây chính là khoảng trống mà security testing automation lấp vào. Trong ngành QA hiện đại, bảo mật không còn là việc của riêng đội pentest cuối kỳ. Với tốc độ release hàng ngày, bạn không thể chờ một đợt penetration test thủ công mỗi quý — lúc đó lỗ hổng đã nằm trên production nhiều tuần. Thay vào đó, chúng ta đưa các công cụ quét bảo mật tự động vào ngay trong pipeline, chạy song song với test chức năng.

Bài này tập trung vào hai trụ cột nền tảng của security automation mà một SDET cần nắm: SAST (quét mã nguồn tĩnh) và DAST (quét ứng dụng đang chạy động). Đây không phải để biến bạn thành hacker, mà để bạn tự tin cắm được lớp phòng thủ bảo mật vào quy trình test hiện có, và biết cách đọc — lọc — hành động trên kết quả quét. Trong bối cảnh Nghị định 13/2023 về bảo vệ dữ liệu cá nhân đã có hiệu lực ở Việt Nam, kỹ năng này càng trở thành lợi thế cạnh tranh rõ rệt.

Khái niệm cốt lõi

SAST — Static Application Security Testing

SAST quét mã nguồn (hoặc bytecode) để tìm lỗ hổng trước khi ứng dụng compile hay chạy. Bạn có thể hình dung SAST như một người soát chính tả cực kỳ am hiểu về bảo mật: nó đọc từng dòng code và cảnh báo "chỗ này bạn nối chuỗi SQL trực tiếp từ input người dùng — nguy cơ SQL Injection".

Đặc điểm của SAST:

  • White-box: nhìn thấy toàn bộ code, hiểu cấu trúc bên trong.
  • Chạy sớm (shift-left): có thể chạy ngay trong IDE, pre-commit hook, hoặc CI khi mở pull request.
  • Bắt được lỗi ở dòng cụ thể: nó chỉ đúng file, đúng số dòng.
  • Điểm yếu — false positive cao: SAST không biết dữ liệu có thực sự đến từ nguồn nguy hiểm hay không, nên hay báo động giả. Nó cũng không thấy lỗi cấu hình runtime hay lỗi logic nghiệp vụ.
Công cụ phổ biến: Semgrep (đa ngôn ngữ, viết rule tùy chỉnh dễ), SonarQube (tích hợp cả quality + security), Bandit (chuyên Python), CodeQL (của GitHub, rất mạnh nhưng dốc học).

Ví dụ chạy Semgrep:

Cài đặt

pip install semgrep

Quét toàn bộ project với ruleset bảo mật có sẵn

semgrep --config=auto .

Quét theo ruleset OWASP Top 10 cho một ngôn ngữ cụ thể

semgrep --config="p/owasp-top-ten" ./src

Xuất kết quả dạng JSON để pipeline đọc

semgrep --config=auto --json --output=semgrep-report.json .

Semgrep còn cho bạn viết rule riêng bằng YAML, ví dụ chặn việc log mật khẩu:

rules:
  - id: no-hardcoded-password
    pattern: password = "..."
    message: "Không hardcode mật khẩu trong source code"
    languages: [python]
    severity: ERROR

DAST — Dynamic Application Security Testing

DAST quét ứng dụng đang chạy thật từ bên ngoài, giống như một hacker thăm dò website của bạn. Nó không cần và không nhìn thấy source code — nó gửi request độc hại (payload) tới các endpoint và quan sát phản hồi để phát hiện lỗ hổng.

Đặc điểm của DAST:

  • Black-box: chỉ tương tác qua HTTP/HTTPS như người dùng bên ngoài.
  • Chạy muộn hơn: cần một môi trường staging đã deploy để quét.
  • Bắt được lỗi runtime thật: XSS, SQL Injection thực sự khai thác được, lỗi cấu hình header, session yếu, HTTPS sai.
  • Ít false positive về khả năng khai thác (vì nó thử tấn công thật), nhưng false negative cao (không quét được code chưa được request chạm tới).
Công cụ phổ biến: OWASP ZAP (miễn phí, mạnh, cực hợp cho automation), Burp Suite (chuẩn công nghiệp cho pentest thủ công), Nikto (quét cấu hình server nhanh).

Ví dụ chạy OWASP ZAP dạng automation bằng Docker:

Baseline scan — nhanh, thụ động, hợp cho chạy mỗi lần deploy

docker run -t owasp/zap2docker-stable zap-baseline.py \ -t https://staging.myapp.vn -r zap-report.html

Full scan — chủ động tấn công, chạy chậm, hợp cho nightly

docker run -t owasp/zap2docker-stable zap-full-scan.py \ -t https://staging.myapp.vn -r zap-full-report.html

SAST vs DAST — hai mặt bổ trợ nhau

Đừng chọn một, hãy dùng cả hai. Chúng bù đắp điểm mù của nhau:

Tiêu chíSASTDAST
Nhìn thấySource codeỨng dụng đang chạy
Thời điểmRất sớm (commit/PR)Sau khi deploy staging
Loại lỗi mạnhCode pattern nguy hiểmLỗ hổng khai thác thực tế
Điểm yếuFalse positive caoKhông thấy code chưa chạy
Cần môi trườngKhôngCó (staging)
Ngoài ra còn có SCA (Software Composition Analysis) — quét các thư viện bên thứ ba xem có dùng phiên bản dính CVE không (công cụ như Trivy, Snyk, npm audit). Đây là mảng riêng nhưng thường được gộp chung vào chiến lược security automation vì hầu hết lỗ hổng thực tế đến từ dependency chứ không phải code bạn tự viết.

Tình huống thực tế

Tình huống 1 — Sàn TMĐT và lỗ hổng thư viện log4j

Một sàn thương mại điện tử tầm trung ở Hà Nội (giả định gọi là ShopViet) có team QA 6 người, backend viết bằng Java Spring Boot. Cuối 2021, khi lỗ hổng Log4Shell (CVE-2021-44228) bùng nổ, cả team hốt hoảng vì không ai biết dịch vụ nào của mình đang dùng log4j phiên bản dính lỗi. Họ mất trọn 2 ngày để dò thủ công qua hàng chục microservice.

Sau sự cố, QA lead quyết định cắm Trivy (SCA) và Semgrep (SAST) vào pipeline. Từ đó, mỗi PR đều tự động quét dependency. Ba tháng sau, Trivy chặn đứng một PR đưa thư viện jackson-databind phiên bản có CVE deserialization vào codebase — trước khi nó kịp lên production.

Bài học: Phần lớn rủi ro bảo mật không nằm ở code bạn viết, mà ở thư viện bạn kéo về. Một SCA scan tự động chỉ mất vài phút cấu hình nhưng cứu bạn khỏi những đêm mất ngủ. SAST và SCA nên là "cổng chặn" bắt buộc trong CI, không phải tùy chọn.

Tình huống 2 — Fintech và endpoint IDOR bị DAST bỏ sót một nửa

Quay lại ví dụ fintech đầu bài. Sau sự cố IDOR, team cắm OWASP ZAP baseline scan vào pipeline staging. Nhưng vài tuần sau, một lỗ hổng XSS ở trang admin lại lọt lưới. Lý do: ZAP baseline chạy ở chế độ thụ động và không đăng nhập được vào khu vực admin — nó chỉ quét được phần public.

Họ sửa bằng cách cấu hình ZAP với authentication context (nạp sẵn session token của tài khoản test), rồi chuyển sang full scan chạy ban đêm. Ngay lần chạy đầu tiên có auth, ZAP tìm ra 3 điểm reflected XSS trong khu vực admin mà baseline scan mù hoàn toàn.

Bài học: DAST chỉ tốt bằng phạm vi mà nó chạm được. Nếu công cụ không đăng nhập được, không đi qua được các luồng phức tạp (giỏ hàng, thanh toán nhiều bước), thì cả một nửa ứng dụng nằm ngoài tầm quét. Đầu tư cấu hình authentication cho DAST là bước quan trọng bậc nhất, đừng bỏ qua vì thấy phiền.

Tình huống 3 — Startup và cơn ác mộng false positive

Một startup SaaS ở Đà Nẵng bật SonarQube với ngưỡng khắt khe ngay từ đầu. Kết quả: lần quét đầu tiên ra hơn 400 security issue. Dev nhìn con số này liền... phớt lờ toàn bộ, vì phần lớn là false positive (ví dụ báo "hardcoded password" cho một biến tên passwordLabel = "Mật khẩu"). Chỉ sau một tuần, cả team coi cảnh báo security như spam.

QA lead phải làm lại từ đầu: tắt bớt rule gây nhiễu, chỉ giữ lại nhóm rule severity cao và thực sự liên quan, đặt baseline "chỉ chặn issue MỚI" thay vì bắt sửa hết nợ cũ. Số cảnh báo giảm còn ~15 issue thật sự đáng quan tâm. Lúc này dev mới thực sự đọc và sửa.

Bài học: Kẻ thù lớn nhất của security automation không phải là thiếu công cụ, mà là alert fatigue — mệt mỏi vì cảnh báo giả. Một công cụ báo 400 lỗi mà bị bỏ qua còn tệ hơn công cụ báo 15 lỗi được sửa. Tinh chỉnh (tuning) quan trọng ngang việc cài đặt.

Hướng dẫn từng bước

Dưới đây là lộ trình cắm security automation vào một dự án thực tế, đi từ dễ tới khó:

Bước 1 — Bắt đầu với SCA, vì nó cho ROI cao nhất. Thêm quét dependency vào CI. Với dự án Node dùng npm audit --audit-level=high; dự án đa ngôn ngữ dùng Trivy: trivy fs --severity HIGH,CRITICAL .. Đây là chiến thắng nhanh, ít false positive.

Bước 2 — Thêm SAST ở tầng pull request. Cài Semgrep với --config=auto. Ban đầu để chế độ cảnh báo, không chặn build (non-blocking), để team làm quen mà không bị chặn công việc. Quan sát 1–2 tuần xem tỷ lệ false positive.

Bước 3 — Tinh chỉnh ruleset. Loại bỏ rule gây nhiễu, thêm rule tùy chỉnh cho pattern nguy hiểm đặc thù dự án bạn (ví dụ: cấm gọi trực tiếp API MoMo mà không verify chữ ký). Đặt baseline: chỉ chặn issue mới phát sinh trong diff, không đòi trả sạch nợ cũ ngay.

Bước 4 — Dựng DAST trên staging. Bắt đầu bằng ZAP baseline scan chạy sau mỗi lần deploy staging. Đây là quét thụ động, nhanh, an toàn — không phá dữ liệu.

Bước 5 — Cấu hình authentication cho DAST. Nạp session token / cookie của tài khoản test để ZAP quét được vùng cần đăng nhập. Đây là bước nâng độ phủ lên gấp đôi.

Bước 6 — Chuyển scan nặng sang lịch nightly. ZAP full scan (chủ động tấn công) chạy chậm và có thể sinh dữ liệu rác, nên đừng chạy trong pipeline chặn merge. Đặt nó chạy ban đêm trên môi trường staging riêng, gửi báo cáo về Slack/Telegram sáng hôm sau.

Bước 7 — Thiết lập cổng chặn (quality gate) và quy trình xử lý. Quy ước rõ: lỗ hổng Critical/High chặn release, Medium tạo ticket xử lý trong sprint, Low ghi nhận theo dõi. Không có quy trình xử lý thì báo cáo chỉ để cho đẹp.

Ví dụ một job trong GitHub Actions gộp SCA + SAST:

name: security-scan
on: [pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: SCA - Trivy
        run: trivy fs --severity HIGH,CRITICAL --exit-code 1 .
      - name: SAST - Semgrep
        run: semgrep --config=auto --error .

Lỗi thường gặp & mẹo

Lỗi 1 — Bật full scan chặn merge ngay từ đầu. Full scan có thể mất 30–60 phút và làm nghẽn pipeline, khiến cả team ghét security. Mẹo: baseline scan cho pipeline, full scan cho nightly.

Lỗi 2 — Chạy DAST trên production. Full scan gửi payload tấn công thật, có thể tạo hàng nghìn record rác, gửi email spam thật cho khách, thậm chí xóa dữ liệu. Luôn quét trên staging với dữ liệu giả. Nếu bắt buộc quét prod, dùng chế độ thụ động và loại trừ các endpoint gây tác dụng phụ.

Lỗi 3 — Bỏ qua cấu hình authentication cho DAST. Không đăng nhập = chỉ quét được vỏ ngoài. Đây là nguyên nhân số một khiến DAST bỏ sót lỗ hổng nghiêm trọng.

Lỗi 4 — Coi mọi cảnh báo là như nhau. Học cách đọc severityCVSS score. Ưu tiên xử lý theo mức độ ảnh hưởng thực tế trên hệ thống của bạn, đừng chạy theo số lượng.

Lỗi 5 — Không có bước triage (phân loại). Cần một người/quy trình lọc false positive trước khi đổ hết cho dev. Nếu không, dev sẽ mất niềm tin và bỏ qua tất cả.

Mẹo quản lý ngoại lệ: Với false positive đã xác nhận, dùng cơ chế "baseline" hoặc "suppress" của công cụ (ví dụ file .semgrepignore, hay đánh dấu "won't fix" trong SonarQube) — ghi rõ lý do — thay vì tắt cả rule. Như vậy rule vẫn bắt được ca mới trong tương lai.

Mẹo về diacritic: Khi test input tiếng Việt, nhớ rằng payload tấn công có thể ẩn trong chuỗi Unicode có dấu; đảm bảo công cụ và ứng dụng xử lý UTF-8 nhất quán để tránh cả false positive lẫn bỏ sót.

Bài tập thực hành

  • SAST cơ bản: Chọn một project mã nguồn mở nhỏ trên GitHub (Python hoặc JS). Chạy semgrep --config=auto . và đọc báo cáo. Chọn ra 3 cảnh báo, tự phân loại đâu là true positive, đâu là false positive, và giải thích lý do.
  • Viết rule tùy chỉnh: Viết một rule Semgrep bằng YAML để phát hiện việc hardcode một API key (ví dụ chuỗi bắt đầu bằng sk_live_). Test rule đó trên một file mẫu bạn tự tạo.
  • DAST với ZAP: Dùng ứng dụng cố tình có lỗ hổng OWASP Juice Shop (chạy bằng Docker: docker run -p 3000:3000 bkimminich/juice-shop). Chạy zap-baseline.py nhắm vào http://localhost:3000 và liệt kê 5 loại lỗ hổng ZAP tìm được.
  • So sánh phủ: Trên cùng Juice Shop, chạy cả baseline scan (không auth) và full scan. So sánh số lượng và loại lỗ hổng tìm được giữa hai lần. Rút ra kết luận về giá trị của authentication + active scan.
  • Thiết kế cổng chặn: Viết một đoạn cấu hình CI (GitHub Actions hoặc GitLab CI) chạy Trivy + Semgrep, chỉ fail build khi có lỗ hổng mức HIGH trở lên, và cho phép Medium/Low đi qua nhưng vẫn in cảnh báo.

Tóm tắt

Security testing automation là kỹ năng đưa bảo mật vào ngay trong quy trình test hàng ngày, thay vì để dồn tới cuối kỳ. Hai trụ cột là SAST — quét mã nguồn tĩnh, chạy sớm, bắt code pattern nguy hiểm nhưng nhiều false positive; và DAST — quét ứng dụng đang chạy, chạy trên staging, bắt lỗ hổng khai thác thực tế nhưng chỉ phủ được phần code được chạm tới. Hai công cụ này bổ trợ nhau, và nên đi kèm SCA để quét thư viện bên thứ ba — nơi phần lớn rủi ro thực sự nằm.

Ba nguyên tắc cốt lõi cần khắc cốt: bắt đầu từ chiến thắng dễ (SCA), luôn tinh chỉnh để tránh alert fatigue, và không bao giờ có báo cáo mà thiếu quy trình xử lý. Bố trí đúng: baseline/SAST/SCA chặn ở PR, full scan chạy nightly, mọi thứ đều trên staging. Làm được vậy, bạn không chỉ là QA chức năng — bạn đã trở thành một SDET biết bảo vệ sản phẩm khỏi những lỗ hổng mà test truyền thống không bao giờ thấy.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi