Semgrep SAST กับ Site Reliability SRE — วิธีใช้
Semgrep คืออะไร

Semgrep เป็นเครื่องมือ Static Analysis แบบ Open-source ที่สแกนหาช่องโหว่ (Vulnerabilities), Bug และ Anti-patterns ใน Source Code โดยไม่ต้องรัน Application จุดเด่นคือเขียน Rules ง่ายด้วย Pattern Matching ที่คล้ายกับ Code จริง ไม่ต้องเรียนรู้ Abstract Syntax Tree (AST) ทำงานเร็วมากเพราะวิเคราะห์แบบ Intra-file
เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ MLflow Experiment Consensus Algorithm
สำหรับ SRE, Semgrep ช่วยป้องกัน Security Incidents ตั้งแต่ Development Phase โดยสแกนหา SQL Injection, XSS, Hardcoded Secrets, Insecure Configuration และ Anti-patterns อื่นๆ ก่อนที่ Code จะถูก Deploy ลด Mean Time to Detection (MTTD) ให้เป็นศูนย์สำหรับ Known Vulnerability Patterns
เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: CDK Construct Site Reliability SRE
ติดตั้งและใช้งาน Semgrep
# ติดตั้ง Semgrep
pip install semgrep
# หรือใช้ Homebrew (macOS)
brew install semgrep
# หรือใช้ Docker
docker pull semgrep/semgrep
# === สแกนด้วย Rules สำเร็จรูป ===
# สแกนด้วย Registry Rules (แนะนำ)
semgrep --config auto .
# สแกนเฉพาะ Security Rules
semgrep --config p/security-audit .
# สแกนเฉพาะภาษา
semgrep --config p/python .
semgrep --config p/javascript .
semgrep --config p/golang .
# สแกนด้วย OWASP Top 10 Rules
semgrep --config p/owasp-top-ten .
# === สแกนด้วย Custom Rules ===
semgrep --config my-rules/ .
# Output Formats
semgrep --config auto --json . # JSON
semgrep --config auto --sarif . # SARIF (GitHub)
semgrep --config auto --junit-xml . # JUnit XML
# === โครงสร้าง Rules Directory ===
semgrep-rules/
├── security/
│ ├── sql-injection.yml
│ ├── xss.yml
│ ├── hardcoded-secrets.yml
│ └── insecure-crypto.yml
├── reliability/
│ ├── error-handling.yml
│ ├── resource-leak.yml
│ └── race-condition.yml
├── best-practices/
│ ├── logging.yml
│ └── config.yml
└── .semgrep.yml # Project Config
# .semgrep.yml — Project Configuration
# paths:
# include:
# - src/
# - lib/
# exclude:
# - tests/
# - node_modules/
# - vendor/
Custom Semgrep Rules
# security/sql-injection.yml — ตรวจจับ SQL Injection
rules:
- id: python-sql-injection
patterns:
- pattern: |
cursor.execute($QUERY % $VAR)
- pattern-not: |
cursor.execute($QUERY, $PARAMS)
message: |
SQL Injection detected. ใช้ Parameterized Query แทน String Formatting
แก้: cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
languages: [python]
severity: ERROR
metadata:
cwe: ["CWE-89"]
owasp: ["A03:2021"]
category: security
confidence: HIGH
- id: python-sql-injection-fstring
pattern: |
cursor.execute(f"...{$VAR}...")
message: |
SQL Injection via f-string. ห้ามใช้ f-string กับ SQL Query
แก้: ใช้ Parameterized Query cursor.execute("... %s ...", (var,))
languages: [python]
severity: ERROR
metadata:
cwe: ["CWE-89"]
- id: js-sql-injection
patterns:
- pattern: |
$DB.query(`... ...`)
- pattern-not: |
$DB.query($QUERY, $PARAMS)
message: |
SQL Injection in template literal. ใช้ Parameterized Query
แก้: db.query("SELECT * FROM users WHERE id = $1", [userId])
languages: [javascript, typescript]
severity: ERROR
# security/hardcoded-secrets.yml — ตรวจจับ Hardcoded Secrets
rules:
- id: hardcoded-api-key
patterns:
- pattern-regex: |
(?i)(api[_-]?key|api[_-]?secret|access[_-]?token)\s*[:=]\s*['"][a-zA-Z0-9_\-]{20,}['"]
message: |
Hardcoded API Key detected. ใช้ Environment Variables แทน
แก้: api_key = os.environ["API_KEY"]
languages: [python, javascript, typescript, go, java]
severity: ERROR
metadata:
cwe: ["CWE-798"]
- id: hardcoded-password
patterns:
- pattern-regex: |
(?i)password\s*[:=]\s*['"][^'"]{8,}['"]
- pattern-not-regex: |
(?i)password\s*[:=]\s*['"](\$\{|os\.environ|process\.env|placeholder|example|changeme)
message: |
Hardcoded password detected. ใช้ Secret Manager หรือ Environment Variables
languages: [python, javascript, typescript]
severity: ERROR
# reliability/error-handling.yml — ตรวจจับ Error Handling ที่ไม่ดี
rules:
- id: python-bare-except
pattern: |
try:
...
except:
...
message: |
Bare except catches all exceptions including SystemExit and KeyboardInterrupt
แก้: except Exception as e: หรือ except SpecificException as e:
languages: [python]
severity: WARNING
metadata:
category: reliability
- id: python-pass-in-except
pattern: |
try:
...
except $E:
pass
message: |
Silent exception handling. อย่างน้อยต้อง Log error
แก้: except Exception as e: logger.error(f"Error: {e}")
languages: [python]
severity: WARNING
- id: go-ignored-error
pattern: |
$VAR, _ = $FUNC(...)
message: |
Error ignored. ต้อง Handle error ใน Go
แก้: result, err := func(); if err != nil { return err }
languages: [go]
severity: WARNING
CI/CD Integration

# .github/workflows/semgrep.yml — GitHub Actions
name: Semgrep Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
semgrep:
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- name: Run Semgrep
run: |
semgrep ci \
--config auto \
--config ./semgrep-rules/ \
--sarif --output=semgrep.sarif \
--json --output=semgrep.json \
--metrics=off
env:
SEMGREP_APP_TOKEN: }
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: semgrep.sarif
- name: Check Critical Findings
if: always()
run: |
CRITICAL=$(cat semgrep.json | python3 -c "
import json, sys
data = json.load(sys.stdin)
critical = [r for r in data.get('results', [])
if r.get('extra', {}).get('severity') == 'ERROR']
print(len(critical))
")
echo "Critical findings: $CRITICAL"
if [ "$CRITICAL" -gt 0 ]; then
echo "CRITICAL vulnerabilities found. Blocking merge."
exit 1
fi
---
# .gitlab-ci.yml — GitLab CI
semgrep:
image: semgrep/semgrep
stage: test
script:
- semgrep ci --config auto --config ./semgrep-rules/ --json
rules:
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == "main"
allow_failure: false
---
# CircleCI Config
version: 2.1
jobs:
semgrep-scan:
docker:
- image: semgrep/semgrep
steps:
- checkout
- run:
name: Semgrep Scan
command: |
semgrep ci \
--config auto \
--config ./semgrep-rules/ \
--json --output=/tmp/semgrep-results.json
- store_artifacts:
path: /tmp/semgrep-results.json
Security SLO สำหรับ SRE
# security_slo_monitor.py — Monitor Security SLO
import json
import time
from datetime import datetime, timedelta
from dataclasses import dataclass
@dataclass
class SecuritySLO:
name: str
target: float # เป็น % หรือ จำนวน
measurement: str # วิธีวัด
window: str # ช่วงเวลา
current_value: float = 0.0
class SecuritySLOMonitor:
"""Monitor Security SLOs สำหรับ SRE"""
def __init__(self):
self.slos = [
SecuritySLO(
"Critical Vulnerability MTTR",
target=24, # ชั่วโมง
measurement="Mean time to remediate Critical findings",
window="30 days",
),
SecuritySLO(
"High Vulnerability MTTR",
target=72, # ชั่วโมง
measurement="Mean time to remediate High findings",
window="30 days",
),
SecuritySLO(
"Scan Coverage",
target=100, # %
measurement="% of repos with Semgrep enabled",
window="continuous",
),
SecuritySLO(
"False Positive Rate",
target=10, # % (ต่ำกว่า)
measurement="% of findings marked as false positive",
window="30 days",
),
SecuritySLO(
"Pre-deploy Block Rate",
target=100, # %
measurement="% of Critical findings blocked before deploy",
window="continuous",
),
]
def check_slos(self, scan_results_path):
"""ตรวจสอบ SLO Status"""
with open(scan_results_path) as f:
results = json.load(f)
findings = results.get("results", [])
critical = [f for f in findings
if f.get("extra", {}).get("severity") == "ERROR"]
high = [f for f in findings
if f.get("extra", {}).get("severity") == "WARNING"]
print("=== Security SLO Dashboard ===")
print(f"Total Findings: {len(findings)}")
print(f"Critical: {len(critical)}")
print(f"High: {len(high)}")
print(f"Timestamp: {datetime.now().isoformat()}")
print(f"\n{'SLO':<35} {'Target':<12} {'Current':<12} {'Status'}")
print("-" * 75)
for slo in self.slos:
status = "PASS" if slo.current_value <= slo.target else "FAIL"
emoji = "OK" if status == "PASS" else "BREACH"
print(f"{slo.name:<35} {slo.target:<12} "
f"{slo.current_value:<12} {emoji}")
# Error Budget
breached = sum(1 for s in self.slos
if s.current_value > s.target)
print(f"\nSLO Status: {len(self.slos) - breached}/{len(self.slos)} passing")
if breached > 0:
print("ACTION REQUIRED: Security SLO breach detected")
print("Recommendation: Pause feature work, focus on security fixes")
monitor = SecuritySLOMonitor()
# monitor.check_slos("semgrep-results.json")
Best Practices
- เริ่มจาก Auto Config: ใช้ semgrep --config auto ก่อน แล้วค่อยเพิ่ม Custom Rules ตาม Codebase
- Block Critical ใน CI: ตั้ง CI ให้ Fail เมื่อพบ Critical/ERROR Findings ปล่อย Warning ผ่านแต่ Track
- ลด False Positives: ใช้ nosemgrep Comment สำหรับ Known False Positives, เขียน Rules ที่ Specific ใช้ pattern-not สำหรับ Exception
- Custom Rules: เขียน Rules สำหรับ Internal Libraries และ Patterns เฉพาะของทีม เช่น ห้ามใช้ Deprecated Functions
- Pre-commit Hook: รัน Semgrep ใน Pre-commit Hook ให้ Developer เห็นปัญหาทันที
- Security SLOs: ตั้ง SLO สำหรับ MTTR ของ Critical Findings, Scan Coverage และ False Positive Rate
- Dashboard: สร้าง Dashboard แสดง Findings Trend, MTTR, SLO Status ให้ทีมเห็น
Semgrep คืออะไร
Semgrep เป็นเครื่องมือ Static Analysis Open-source สแกนหาช่องโหว่ Bug และ Anti-patterns ใน Source Code รองรับกว่า 30 ภาษา เขียน Rules ง่ายด้วย Pattern Matching ทำงานเร็ว ใช้ใน CI/CD Pipeline ป้องกัน Vulnerable Code ก่อน Deploy
แนะนำเพิ่มเติม — iCafeForex
เนื้อหาเกี่ยวข้อง — RAG Architecture Observability Stack





