AppSec 7 — DevSecOps & công cụ tự động

13 thg 7, 2026 3 lượt xem
#security
#ci-cd
#devops
#devsecops
#sast
#dast

AppSec 7 — DevSecOps & công cụ tự động

Sáu bài trước của series bàn về cái gì cần bảo vệ: tổng quan AppSec, OWASP Top 10, injection & authentication, access control & crypto, secrets & supply chain, và API security. Bài này trả lời câu hỏi khác — làm sao đảm bảo những nguyên tắc đó không bị quên trong mỗi lần deploy. Câu trả lời không phải là "review kỹ hơn", mà là tự động hoá: biến kiểm tra bảo mật thành một phần của pipeline CI/CD, chạy trên từng commit, không phụ thuộc vào việc ai đó nhớ hay không.

Đây chính là DevSecOps: đưa bảo mật (Sec) chen vào giữa Dev và Ops, dịch trách nhiệm bảo mật từ một đội "gác cổng cuối cùng" thành thứ được kiểm tra liên tục, tự động, sớm. Khẩu hiệu quen thuộc là shift-left — dịch việc kiểm tra bảo mật về bên trái của dòng thời gian phát triển, càng gần lúc viết code càng tốt. Bài này biến shift-left từ slogan thành các bước cụ thể.

Vì sao shift-left: chi phí của việc phát hiện muộn

Một lỗ hổng phát hiện lúc developer đang gõ code tốn vài phút để sửa. Cùng lỗ hổng đó lọt tới production của một hệ thống ngân hàng có thể tốn hàng tháng khắc phục, chưa kể sự cố rò rỉ dữ liệu và báo cáo cơ quan quản lý. Chi phí sửa lỗi tăng theo cấp số nhân theo từng giai đoạn nó bị bỏ sót.

Ý nghĩa thực tế của shift-left: đừng đợi pentest cuối cùng để tìm SQL injection; hãy để một công cụ quét ngay khi code chưa merge. Tự động hoá làm được điều review thủ công không làm nổi — chạy trên mọi commit, nhất quán, không mệt mỏi, không thiên vị.

Các loại kiểm thử bảo mật & khi nào chạy

Không có một công cụ "quét bảo mật" duy nhất. Có nhiều loại kiểm thử, mỗi loại nhìn ứng dụng từ một góc khác nhau và bắt được lớp lỗi khác nhau. Hiểu đúng từng loại để đặt đúng chỗ trong pipeline.

SAST — Static Application Security Testing

SAST quét mã nguồn tĩnh — đọc code (hoặc bytecode) mà không chạy ứng dụng, tìm mẫu lỗi: nối chuỗi vào câu SQL (injection), dùng hàm crypto lỗi thời, hardcode secret, tham số chưa kiểm tra. Nó nhìn từ bên trong (white-box), thấy được đường đi của dữ liệu trong code.

  • Công cụ tiêu biểu: Semgrep, SonarQube, CodeQL (GitHub), Checkmarx.
  • Chạy khi nào: rất sớm — trong IDE, trên mỗi commit, và ở bước PR. Đây là công cụ shift-left nhất.
  • Ưu: phát hiện sớm, ngay khi code còn trong tay dev; chỉ đúng dòng lỗi; nhanh; không cần môi trường chạy.
  • Nhược: false positive cao — báo lỗi ở chỗ thực ra an toàn (ví dụ báo injection nhưng input đã được kiểm tra ở tầng khác). Không thấy lỗi runtime hay lỗi cấu hình môi trường. Cần tinh chỉnh luật (tune rules) để không "kêu cứu" quá nhiều đến mức dev bỏ qua hết.

DAST — Dynamic Application Security Testing

DAST làm ngược lại: quét ứng dụng đang chạy như một hộp đen (black-box), không cần biết code bên trong. Nó gửi request tấn công thật (payload injection, thử XSS, thử vượt authentication) vào ứng dụng đã deploy và quan sát phản hồi.

  • Công cụ tiêu biểu: OWASP ZAP, Burp Suite.
  • Chạy khi nào: muộn hơn — sau khi đã deploy lên môi trường test/staging, vì cần app thật đang chạy.
  • Ưu: tìm được lỗi runtime mà SAST không thấy — lỗi cấu hình server, TLS sai, header bảo mật thiếu, hành vi thực tế của luồng auth. Ít false positive hơn về mặt "có khai thác được không" (vì nó thử tấn công thật).
  • Nhược: chậm, cần môi trường chạy; coverage phụ thuộc vào việc nó "mò" tới được endpoint nào — không quét được nhánh code không được kích hoạt; không chỉ ra dòng code lỗi (chỉ báo "endpoint này thủng").

SAST và DAST bổ sung cho nhau, không thay thế: một cái nhìn code, một cái nhìn hành vi. Một hệ thống nghiêm túc dùng cả hai.

IAST & RASP — sơ lược

  • IAST (Interactive AST) — lai giữa SAST và DAST: cài agent bên trong ứng dụng đang chạy (thường trong lúc test tự động), quan sát luồng dữ liệu runtime để xác nhận lỗ hổng có thật. Kết hợp độ chính xác của "chạy thật" với việc chỉ ra được vị trí code. Đổi lại: cần tích hợp agent, phủ đến đâu tuỳ test chạy đến đâu.
  • RASP (Runtime Application Self-Protection) — không phải công cụ kiểm thử mà là bảo vệ runtime: agent nhúng trong app production, phát hiện và chặn tấn công ngay khi đang xảy ra (như một WAF nằm bên trong ứng dụng). Thuộc phòng thủ vận hành hơn là CI/CD.

SCA — Software Composition Analysis

SCA quét thư viện phụ thuộc (dependencies) để tìm CVE đã biết — lỗ hổng công bố công khai trong các package bên thứ ba mà dự án đang dùng. Đây là mặt trận supply chain đã bàn kỹ ở bài Secrets & Supply Chain. Công cụ: Trivy, Grype, Dependabot, npm audit, OWASP Dependency-Check. Chạy sớm (trên PR) và định kỳ (để bắt CVE mới công bố sau khi code đã merge).

Secret scanning

Quét mã nguồn và lịch sử git tìm secret bị hardcode — API key, mật khẩu, token, private key vô tình commit. Cũng đã bàn ở bài 5. Công cụ: Gitleaks, TruffleHog, detect-secrets. Nên chạy ở pre-commit hook (chặn trước khi secret kịp lên git) trong CI (lưới an toàn).

Container image scanning

Ứng dụng đóng gói thành container image (xem Dockerfile & image). Image chứa cả OS base, thư viện hệ thống, dependencies — mỗi lớp đều có thể mang CVE. Image scanning quét toàn bộ image tìm lỗ hổng đã biết trong các gói đó.

  • Công cụ: Trivy, Grype, Clair.
  • Chạy khi nào: sau bước build image, trước khi push lên registry / deploy.
  • Đây là điểm mù mà SAST/SCA code-level bỏ lỡ: bạn viết code sạch nhưng base image debian:11 lại có OpenSSL dính CVE nghiêm trọng.

IaC scanning

Hạ tầng ngày nay là code — Terraform, Kubernetes manifest, Dockerfile, Helm chart. IaC scanning quét các file cấu hình này tìm cấu hình sai (misconfiguration): S3 bucket để public, security group mở port 0.0.0.0/0, container chạy quyền root, thiếu mã hoá at-rest.

  • Công cụ: tfsec, Checkov, Terrascan, kube-score.
  • Chạy khi nào: trên PR thay đổi hạ tầng, và trước khi apply.
  • Bắt được lớp lỗi hoàn toàn khác code: không phải bug logic mà là "cấu hình mở toang cánh cửa".

DAST API

Biến thể của DAST nhắm riêng API (REST/GraphQL). Thay vì "mò" giao diện web, nó nạp đặc tả API (OpenAPI/Swagger) rồi thử tấn công từng endpoint: BOLA/IDOR, thiếu rate limit, mass assignment — đúng các rủi ro trong bài API Security. Hợp với hệ thống ngân hàng vốn phơi bày nhiều API dữ liệu.

Bảng tổng hợp

LoạiNhìn gìChạy khi nàoBắt lỗi gìĐiểm yếu
SASTMã nguồn (tĩnh)IDE, commit, PRInjection, crypto yếu, code lỗiFalse positive cao
DASTApp đang chạy (hộp đen)Sau deploy stagingLỗi runtime, cấu hình, authChậm, coverage phụ thuộc
IASTApp + agent bên trongTrong test tự độngXác nhận lỗ hổng runtimeCần tích hợp agent
SCADependenciesPR + định kỳCVE thư viện bên thứ baChỉ bắt lỗ hổng đã biết
Secret scanCode + lịch sử gitPre-commit + CISecret hardcodeCần xoay khoá khi lộ
Image scanContainer imageSau build imageCVE trong OS/lib của imageKhông thấy lỗi logic app
IaC scanTerraform/K8s configPR hạ tầng + pre-applyCấu hình sai, quyền quá rộngKhông kiểm tra runtime

Xây dựng security pipeline

Có công cụ chưa đủ — phải sắp xếp chúng vào pipeline với các cổng (gate) rõ ràng. Cổng là điểm mà CI chặn build (fail) nếu phát hiện lỗ hổng vượt ngưỡng, buộc phải xử lý trước khi đi tiếp.

Thứ tự có chủ ý: các bước nhanh và rẻ (secret, SAST, SCA) chạy trước, fail sớm để tiết kiệm thời gian; các bước chậm và tốn tài nguyên (DAST cần deploy) chạy sau. Đây gọi là "fail fast".

Quản lý ngưỡng & phân loại severity

Điểm mấu chốt của cổng: chặn cái gì. Không phải mọi phát hiện đều đáng chặn build. Cần chính sách rõ ràng theo severity (mức nghiêm trọng, thường dựa trên CVSS: Critical / High / Medium / Low):

  • Critical / Highfail build, không cho merge/deploy.
  • Medium → cảnh báo, tạo ticket theo dõi, không chặn (hoặc chặn theo ngữ cảnh).
  • Low / Info → ghi nhận, ưu tiên thấp.

Ngưỡng phải được quản lý tập trung và thống nhất, có cơ chế exception có kiểm soát (waiver): khi một phát hiện được xác nhận là false positive hoặc chấp nhận rủi ro tạm thời, phải có người phê duyệt và ghi lại lý do + thời hạn — chứ không phải dev tự tắt cảnh báo.

Cạm bẫy: chặn quá mức

Đây là sai lầm phổ biến nhất khi triển khai security pipeline. Nếu cổng quá gắt (fail cả Low, không tune false positive), pipeline biến thành "báo động giả liên miên". Hậu quả tâm lý: dev mất niềm tin, coi mọi cảnh báo là nhiễu, và bắt đầu bỏ qua tất cả — kể cả lỗ hổng thật (hiện tượng alert fatigue). Một cổng chặn 100% commit vì Low severity thực ra kém an toàn hơn một cổng chỉ chặn Critical/High mà dev thực sự tôn trọng.

Nguyên tắc: cổng phải đáng tin. Tune công cụ để giảm false positive; chỉ chặn ở mức thực sự đáng chặn; mọi lần fail phải có tín hiệu rõ ràng để hành động. An toàn đến từ việc dev tin và làm theo cổng, không đến từ việc cổng gắt nhất có thể.

Quản lý lỗ hổng (Vulnerability Management)

Phát hiện chỉ là bước đầu. Một lỗ hổng tìm thấy rồi để đó thì cũng như không tìm. Cần quy trình vòng đời:

  1. Triage (phân loại) — sàng lọc phát hiện: cái nào thật, cái nào false positive, mức độ nghiêm trọng thực tế trong ngữ cảnh (một CVE "Critical" trong thư viện không dùng đến có thể hạ ưu tiên).
  2. Theo dõi (track) — mỗi lỗ hổng thật thành một ticket, có người sở hữu, trạng thái. Nhiều đội dùng nền tảng DefectDojo hoặc tích hợp thẳng vào Jira để gom kết quả từ nhiều công cụ về một chỗ, khử trùng lặp.
  3. Vá theo SLA — đặt thời hạn xử lý theo severity. Ví dụ chính sách (minh hoạ): Critical vá trong 7 ngày, High 30 ngày, Medium 90 ngày. SLA biến "sẽ sửa lúc nào đó" thành cam kết đo được — cực kỳ quan trọng với hệ thống chịu tuân thủ.
  4. Xác nhận đóng (verify) — lỗ hổng chỉ đóng khi bản vá được kiểm chứng (scan lại xanh), không đóng chỉ vì "đã push code".

Văn hoá DevSecOps

Công cụ không tự tạo ra bảo mật; con người và quy trình mới quyết định. DevSecOps trước hết là thay đổi văn hoá:

  • Bảo mật là trách nhiệm chung — không còn "đội security lo phần đó". Mỗi developer chịu trách nhiệm về code an toàn của mình; đội security chuyển vai trò từ gác cổng sang enabler (cung cấp công cụ, hướng dẫn, guardrail).
  • Security champion — trong mỗi team dev có một người được đào tạo sâu hơn về bảo mật, làm cầu nối với đội security, review các thay đổi nhạy cảm và lan toả kiến thức. Mô hình này scale bảo mật mà không cần đội security khổng lồ.
  • Threat modeling sớm — ngồi lại ngay từ khâu thiết kế để hỏi "hệ thống này bị tấn công thế nào?", "dữ liệu nhạy cảm đi qua đâu?", "ai được truy cập gì?". Phương pháp phổ biến: STRIDE (Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege). Tìm lỗ hổng trên bản vẽ rẻ hơn tìm trên production rất nhiều.

Pentest & bug bounty — bổ sung cho tự động

Tự động hoá mạnh nhưng có giới hạn: công cụ bắt các mẫu đã biết. Lỗ hổng logic nghiệp vụ (ví dụ: quy trình chuyển tiền cho phép số tiền âm, hay race condition rút tiền hai lần) thường vượt tầm với của scanner — cần đầu óc con người.

  • Pentest (kiểm thử xâm nhập) — chuyên gia bảo mật (nội bộ hoặc thuê ngoài) chủ động tấn công hệ thống theo lịch định kỳ hoặc trước mỗi mốc lớn. Sâu, sáng tạo, bắt được lỗi logic; đắt và không liên tục.
  • Bug bounty — mời cộng đồng researcher tìm lỗi, trả thưởng theo mức độ nghiêm trọng. Phủ rộng và liên tục; cần độ trưởng thành nhất định về quy trình xử lý báo cáo.

Tự động (CI/CD) lo chiều rộng và tần suất; pentest/bug bounty lo chiều sâu và sáng tạo. Cả hai cùng cần.

Đo lường

Không đo thì không cải thiện được. Vài chỉ số cốt lõi của một chương trình DevSecOps:

  • MTTR bảo mật (Mean Time To Remediate) — thời gian trung bình từ lúc phát hiện đến lúc vá xong, tách theo severity. Xu hướng giảm = chương trình đang khoẻ.
  • Số lỗ hổng thoát ra prod (escaped vulnerabilities) — bao nhiêu lỗ hổng bị các cổng bỏ lọt và chỉ phát hiện ở production/pentest. Càng ít nghĩa là cổng càng hiệu quả.
  • Tỷ lệ tuân thủ SLA — phần trăm lỗ hổng được vá đúng hạn theo severity.
  • Coverage — bao nhiêu % repo/service đã bật đủ SAST/SCA/secret/image scan trong pipeline.

Ví dụ CI minh hoạ

Dưới đây là một pipeline security minh hoạ (không phải cấu hình production hoàn chỉnh), thể hiện thứ tự cổng và cách fail theo severity:

# .gitlab-ci.yml (minh hoạ)
stages: [scan, build, image-scan, dast]

secret-scan:          # nhanh nhất, chạy trước
  stage: scan
  script: gitleaks detect --source . --exit-code 1   # lộ secret -> fail

sast:
  stage: scan
  script: semgrep ci --error   # chỉ fail ở mức High trở lên

sca:
  stage: scan
  script: trivy fs --severity CRITICAL,HIGH --exit-code 1 .

iac-scan:
  stage: scan
  script: checkov -d infra/ --hard-fail-on HIGH

build:
  stage: build
  script: docker build -t app:$CI_COMMIT_SHA .

image-scan:           # sau khi có image
  stage: image-scan
  script: trivy image --severity CRITICAL,HIGH --exit-code 1 app:$CI_COMMIT_SHA

dast:                 # chậm nhất, chạy cuối trên staging
  stage: dast
  script: zap-baseline.py -t https://staging.internal -I   # -I: không fail ở cảnh báo info

Điểm cần lưu ý: mỗi bước dùng cờ severity (--severity CRITICAL,HIGH, --hard-fail-on HIGH) để chỉ chặn ở mức đáng chặn, đúng nguyên tắc "cổng phải đáng tin" ở trên.

Use case thực tế

Bối cảnh. Đội dữ liệu NCB vận hành một hệ thống API cung cấp dữ liệu khách hàng (data serving layer) cho các phòng nghiệp vụ. Trước đây bảo mật chỉ được kiểm ở một đợt pentest hằng năm; kết quả là mỗi lần pentest lại "đào" ra hàng chục lỗ hổng đã tồn tại nhiều tháng, và việc vá dồn cục gây trễ release. Đội quyết định dựng security pipeline theo DevSecOps.

Triển khai (theo 4 tuần).

  1. Tuần 1 — chặn máu chảy. Bật Gitleaks pre-commit + CISemgrep trên PR. Ngay lập tức bắt được 2 access key AWS hardcode trong nhánh feature chưa merge và một chuỗi nối SQL có nguy cơ injection ở module báo cáo.
  2. Tuần 2 — supply chain. Thêm Trivy quét dependency và image scan sau build. Phát hiện base image cũ dính một CVE OpenSSL mức Critical → cập nhật base image, dựng lại.
  3. Tuần 3 — hạ tầng & runtime. Thêm Checkov quét Terraform (bắt một security group mở cổng DB ra 0.0.0.0/0) và OWASP ZAP DAST trên staging (bắt thiếu header bảo mật + một endpoint API chưa rate limit).
  4. Tuần 4 — quy trình. Đặt cổng theo severity (Critical/High fail build), gom kết quả về DefectDojo, đặt SLA (Critical 7 ngày, High 30 ngày), và chỉ định security champion cho đội.

Kết quả sau một quý. Số lỗ hổng "thoát ra prod" trong đợt pentest tiếp theo giảm mạnh — phần lớn đã bị chặn ngay tại PR. MTTR Critical rút từ "vài tuần" xuống trong SLA 7 ngày. Quan trọng không kém: đội tune false positive của Semgrep trong 2 tuần đầu để cổng không kêu bừa, nhờ đó dev tôn trọng cổng thay vì tìm cách vòng qua. Bối cảnh tuân thủ: có bằng chứng kiểm tra bảo mật tự động trên từng thay đổi là tài liệu quý khi làm việc với kiểm toán và cơ quan quản lý.

Ghi nhớ

  • DevSecOps = nhúng bảo mật tự động vào CI/CD, biến shift-left từ khẩu hiệu thành gate chạy trên mỗi commit. Chi phí sửa lỗ hổng tăng theo cấp số nhân càng phát hiện muộn.
  • SAST quét mã nguồn tĩnh (sớm, nhưng false positive cao); DAST quét app đang chạy như hộp đen (bắt lỗi runtime, chậm). Hai cái bổ sung nhau, không thay thế.
  • Đủ họ công cụ, mỗi loại một lớp lỗi: SCA (CVE dependency), secret scanning, container image scanning (Trivy/Grype), IaC scanning (tfsec/Checkov — cấu hình sai), DAST API.
  • Security pipeline sắp xếp công cụ theo "fail fast": nhanh/rẻ (secret, SAST, SCA) trước, chậm (DAST) sau; có cổng chặn build theo severity.
  • Cạm bẫy lớn nhất: chặn quá mức. Cổng gắt bừa gây alert fatigue → dev bỏ qua tất cả. Tune false positive, chỉ chặn Critical/High; cổng phải đáng tin thì dev mới tôn trọng.
  • Quản lý lỗ hổng: triage → track (DefectDojo/Jira) → vá theo SLA theo severity → verify đóng. Phát hiện mà không theo dõi thì vô nghĩa.
  • Văn hoá: bảo mật là trách nhiệm chung, có security champion trong mỗi đội, threat modeling (STRIDE) sớm từ khâu thiết kế.
  • Pentest & bug bounty bổ sung cho tự động — bắt lỗi logic nghiệp vụ mà scanner không thấy. Tự động lo bề rộng/tần suất; con người lo chiều sâu.
  • Đo lường: MTTR theo severity, số lỗ hổng thoát ra prod, tỷ lệ tuân thủ SLA, coverage pipeline.

Bài viết liên quan

Container vs máy ảo, image/layer, Dockerfile, volume, network, Docker Compose và best practices.

13 thg 7, 2026 3

Continuous Integration/Delivery/Deployment, cấu trúc pipeline, ví dụ GitHub Actions và chiến lược release.

13 thg 7, 2026 3

Vì sao cần orchestration; Pod, Deployment, Service, Ingress; scaling, self-healing và cấu hình.

13 thg 7, 2026 3

Bản chất DevOps: phá bỏ rào cản Dev–Ops, vòng lặp vô tận, CALMS, và vì sao tự động hoá.

13 thg 7, 2026 3