Tools

Semgrep: phân tích tĩnh với quy tắc viết như chính code cần tìm

Tóm tắt

Semgrep hỗ trợ hơn 30 ngôn ngữ, quy tắc viết bằng mẫu giống code ($X, ...). Bắt đầu với --config auto hoặc p/ci, rồi viết quy tắc cho lỗi team từng gặp. Bản Community chỉ phân tích trong một hàm hoặc file.

Code review bắt được nhiều lỗi, nhưng con người mệt mỏi và hay bỏ sót những mẫu lặp lại: gọi eval với dữ liệu người dùng, ghép chuỗi SQL, tắt kiểm tra chứng chỉ, quên kiểm tra quyền. Linter thông thường chủ yếu bắt lỗi định dạng và cú pháp. Semgrep là công cụ phân tích tĩnh nhẹ, hỗ trợ hơn 30 ngôn ngữ, điểm đặc biệt là quy tắc được viết bằng mẫu trông giống chính code cần tìm, nên dev tự viết được quy tắc cho codebase của mình chỉ trong vài phút.

Trang GitHub của semgrep/semgrep
Trang GitHub của semgrep/semgrep (ảnh chụp tháng 11/2026)

GitHub: https://github.com/semgrep/semgrep · khoảng 17 nghìn sao · OCaml/C · LGPL-2.1

Cài đặt

brew install semgrep      # macOS
pip install semgrep       # hoặc: pipx install semgrep / uv tool install semgrep
docker run -it -v "${PWD}:/src" semgrep/semgrep semgrep scan --config auto

Quét với bộ quy tắc có sẵn

semgrep scan --config auto                 # tự chọn quy tắc theo ngôn ngữ trong project
semgrep scan --config p/owasp-top-ten      # bộ quy tắc theo OWASP Top 10
semgrep scan --config p/ci                 # bộ quy tắc gọn cho CI
semgrep scan --config p/python --error     # trả mã lỗi nếu có phát hiện

Các bộ quy tắc p/... lấy từ Semgrep Registry. Theo README, dùng cấu hình từ Registry sẽ gửi số liệu sử dụng ẩn danh về semgrep.dev; dùng file quy tắc cục bộ thì không gửi khi chưa đăng nhập.

Viết quy tắc riêng

Đây là phần mạnh nhất. Ví dụ chặn việc ghép chuỗi vào câu SQL trong Python:

# rules/sql-injection.yml
rules:
  - id: no-string-concat-in-sql
    languages: [python]
    severity: ERROR
    message: Không ghép chuỗi vào SQL, hãy dùng tham số (?, %s)
    patterns:
      - pattern-either:
          - pattern: $CURSOR.execute("..." + $X)
          - pattern: $CURSOR.execute(f"...")
      - pattern-not: $CURSOR.execute("...", ...)
semgrep scan --config rules/
Cú phápÝ nghĩa
$XMetavariable: khớp một biểu thức bất kỳ và nhớ lại để so sánh
...Khớp mọi thứ: tham số, câu lệnh, chuỗi
pattern-eitherKhớp một trong các mẫu (HOẶC)
pattern-notLoại trừ trường hợp an toàn
pattern-insideChỉ khớp khi nằm bên trong một cấu trúc (ví dụ trong hàm xử lý request)

Thử quy tắc nhanh trên trình duyệt tại Semgrep Playground trước khi đưa vào repo.

Đưa vào CI

# Trong GitHub Actions, không cần tài khoản
- run: pipx run semgrep scan --config p/ci --config rules/ --error --sarif -o semgrep.sarif

File SARIF có thể tải lên tab Security của GitHub để kết quả hiện ngay trên PR. Dùng comment nosemgrep trên dòng code để bỏ qua báo động nhầm, kèm lý do.

Giới hạn cần biết

  • Theo README, bản Community Edition chỉ phân tích trong phạm vi một hàm hoặc một file, nên trong bối cảnh bảo mật sẽ bỏ sót nhiều lỗi thật cần phân tích luồng dữ liệu xuyên file. Phân tích sâu hơn thuộc nền tảng trả phí.
  • Quy tắc quá rộng tạo nhiều báo động nhầm và team sẽ bỏ qua; bắt đầu ít quy tắc, độ chính xác cao.
  • Semgrep bổ sung chứ không thay thế code review và kiểm thử bảo mật.

Áp dụng thế nào?

  • Dev: Chạy semgrep scan --config auto trên project để thấy các mẫu rủi ro hiện có; sau mỗi lỗi bảo mật được sửa, viết một quy tắc để nó không quay lại.
  • Tech Lead: Biến các quy ước nội bộ ("không gọi API X trực tiếp", "luôn dùng hàm sanitize Y") thành quy tắc Semgrep chạy trong CI, thay vì nhắc trong review.
  • PM: Mỗi lỗi đã gặp trở thành một kiểm tra tự động, chi phí phát hiện giảm theo thời gian thay vì lặp lại.

Nguồn & tham khảo

  1. semgrep/semgrep — semgrep (GitHub)
  2. Semgrep documentation — semgrep