Dùng Semgrep để ‘vây bắt’ lỗ hổng bảo mật: Nhanh, chuẩn và cực kỳ dễ viết rule

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

Review code thủ công: Khi nỗ lực không thể bù đắp quy mô

Hồi mới làm lead, mình thường tốn 3-4 tiếng mỗi ngày chỉ để soi từng dòng code của anh em trước khi merge. Nỗi sợ lớn nhất không phải là logic sai. Đó là những lỗ hổng bảo mật sơ đẳng như SQL Injection, lộ Secret hay các hàm unsafe. Mình từng audit hơn 10 dự án thực tế. Kết luận rút ra khá phũ phàng: hầu hết lỗ hổng nghiêm trọng đều do những dòng code sơ hở mà chúng ta thường bỏ qua khi bị deadline “dí”.

Review thủ công rõ ràng là không thể scale. Đó là lý do mình tìm đến các công cụ SAST (Static Application Security Testing). Tuy nhiên, trải nghiệm ban đầu khá tệ. Những công cụ đời đầu thường rất nặng nề và trả về hàng tá kết quả “dương tính giả” (false positives). Mọi thứ chỉ thay đổi khi mình chuyển sang dùng Semgrep trên production suốt 6 tháng qua.

Tại sao Semgrep lại khác biệt so với phần còn lại?

Để hiểu tại sao Semgrep đáng dùng, hãy nhìn vào 3 hướng tiếp cận phổ biến mà mình đã từng thử nghiệm.

1. Grep truyền thống

Dùng lệnh grep để tìm password hay eval() là cách nhanh nhất. Thế nhưng, nó cực kỳ thiếu linh hoạt vì không hiểu ngữ cảnh. Nếu bạn đặt tên biến là my_password_label, grep vẫn báo lỗi, gây nhiễu thông tin khủng khiếp.

2. Các “ông lớn” như SonarQube hay Snyk

Đây là những giải pháp rất mạnh mẽ. Tuy nhiên, SonarQube thường yêu cầu tối thiểu 2GB RAM chỉ để chạy nền, quá nặng cho các dự án nhỏ. Việc viết thêm rule tùy chỉnh (custom rules) cho riêng dự án cũng là một thử thách thực sự với cú pháp phức tạp.

3. Semgrep – Sự cân bằng hoàn hảo

Semgrep (Semantic Grep) hiểu được cấu trúc cú pháp nhưng lại có tốc độ nhanh như grep. Nó nhận diện được $X = 1; $X + 2$VAR = 1; $VAR + 2 là cùng một pattern. Điểm mình thích nhất là cú pháp viết rule cực kỳ giống code thật. Bạn không cần phải là chuyên gia về AST (Abstract Syntax Tree) vẫn có thể dùng tốt.

3 lý do mình tin dùng Semgrep cho dự án Production

Sau nửa năm áp dụng, mình đúc kết được những con số thực tế đầy thuyết phục:

  • Tốc độ cực ấn tượng: Trong khi các tool cũ mất 15 phút, Semgrep quét xong 1.000 file chỉ trong chưa đầy 30 giây.
  • Tùy biến trong 5 phút: Mình có thể viết ngay một rule để cấm team dùng một thư viện cũ hoặc bắt buộc check quyền trước khi gọi hàm.
  • Hệ sinh thái sẵn có: Semgrep Registry cung cấp hơn 2.000 rule từ cộng đồng (OWASP Top 10, framework-specific) để bạn dùng ngay lập tức.

Triển khai Semgrep chỉ với vài dòng lệnh

Bạn không cần cấu hình server phức tạp. Semgrep chạy trực tiếp qua Docker hoặc cài nhanh qua Python pip.

1. Cài đặt

Trên máy local hoặc server CI, hãy chạy lệnh:

python3 -m pip install semgrep

Hoặc dùng Docker nếu bạn muốn môi trường sạch sẽ:

docker run --rm -v $(pwd):/src returntocorp/semgrep semgrep --config=auto

2. Quét dự án đầu tiên

Hãy di chuyển vào thư mục code và thực hiện lệnh quét tự động. Semgrep sẽ tự nhận diện ngôn ngữ và áp dụng các rule chuẩn nhất.

semgrep scan --config auto

Kết quả hiện ra rất trực quan. Nó chỉ rõ file nào, dòng nào vi phạm kèm theo hướng dẫn khắc phục cụ thể.

Tự viết Custom Rule: Biến Semgrep thành “vệ sĩ” riêng

Đây là phần giá trị nhất. Giả sử bạn muốn cấm dùng hàm os.system() trong Python vì nó dễ bị Command Injection. Bạn muốn team chuyển sang dùng subprocess an toàn hơn.

Hãy tạo file my-rules.yaml:

rules:
  - id: avoid-os-system
    patterns:
      - pattern: os.system(...)
    message: "Cảnh báo: Đừng dùng os.system(). Hãy thay bằng subprocess.run(shell=False)."
    languages: [python]
    severity: ERROR

Dấu ... (ellipsis) là vũ khí bí mật. Nó đại diện cho “bất kỳ tham số nào”. Đây là điểm vượt trội hoàn toàn so với Regex truyền thống.

Tích hợp vào CI/CD: Chặn lỗi từ “vòng gửi xe”

Đừng đợi đến lúc deploy mới quét. Mình luôn tích hợp Semgrep vào GitHub Actions để kiểm tra mỗi khi có Pull Request. Nếu phát hiện lỗi mức ERROR, hệ thống sẽ chặn không cho merge.

Cấu hình .github/workflows/semgrep.yml tham khảo:

name: Semgrep SAST
on:
  pull_request: {}
jobs:
  semgrep:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run Scan
        run: |
          python3 -m pip install semgrep
          semgrep scan --config auto --error

Kinh nghiệm thực tế: Đừng để False Positives làm phiền

Dù thông minh, thỉnh thoảng Semgrep vẫn báo nhầm. Ví dụ, một đoạn code test chứa mật khẩu giả lập cũng có thể bị gắn cờ. Thay vì tắt cả rule, hãy dùng tính năng inline ignore.

Chỉ cần thêm comment ngay trên dòng bị báo lỗi:

# nosemgrep
password = "test_password_123"

Cách này giúp team kiểm soát ngoại lệ mà không làm hổng hàng rào bảo mật chung.

Lời kết

Từ khi áp dụng Semgrep, số lượng bug bảo mật lọt xuống staging của team mình giảm rõ rệt. Quan trọng hơn, nó giúp anh em hình thành thói quen viết code an toàn hơn mỗi ngày. Nếu bạn cần một công cụ SAST nhẹ, nhanh và dễ học, Semgrep chắc chắn là lựa chọn số một.

Đừng đợi đến khi dữ liệu bị rò rỉ mới lo bảo mật. Hãy cài Semgrep và quét dự án của bạn ngay hôm nay. Kết quả có thể sẽ khiến bạn bất ngờ đấy!

Share: