Initial commit from template
This commit is contained in:
148
.claude/skills/semgrep-security/SKILL.md
Normal file
148
.claude/skills/semgrep-security/SKILL.md
Normal file
@@ -0,0 +1,148 @@
|
||||
---
|
||||
name: semgrep-security
|
||||
description: Security Scanner mit Semgrep. WICHTIG - Dieser Skill wird automatisch bei JEDER Code-Implementierung aktiviert. Scannt neuen und geaenderten Code auf Sicherheitsluecken, Vulnerabilities und Best Practice Verstoesse. Aktiviert bei Begriffen wie "implementieren", "code schreiben", "feature erstellen", "komponente bauen", "funktion erstellen", "api route", "fertig", "done", "commit", "security", "scan", "vulnerabilities", "sicherheit".
|
||||
---
|
||||
|
||||
# Semgrep Security Scanner
|
||||
|
||||
Dieser Skill scannt automatisch Code auf Sicherheitsprobleme nach jeder Implementierung.
|
||||
|
||||
## WICHTIG: Automatische Ausfuehrung
|
||||
|
||||
Nach JEDER Code-Implementierung fuehre folgende Schritte aus:
|
||||
|
||||
1. **Semgrep installieren** (falls nicht vorhanden)
|
||||
2. **Geaenderte Dateien scannen**
|
||||
3. **Probleme fixen oder reporten**
|
||||
|
||||
## Scripts
|
||||
|
||||
### Installation pruefen und durchfuehren
|
||||
```bash
|
||||
bash install-semgrep.sh
|
||||
```
|
||||
|
||||
### Scan durchfuehren
|
||||
```bash
|
||||
# Alle Dateien scannen
|
||||
bash scan.sh
|
||||
|
||||
# Nur bestimmte Dateien scannen
|
||||
bash scan.sh app/api/users/route.ts components/UserForm.tsx
|
||||
```
|
||||
|
||||
### Autofix anwenden
|
||||
```bash
|
||||
bash autofix.sh
|
||||
```
|
||||
|
||||
## Workflow nach Implementierung
|
||||
|
||||
### 1. Installation sicherstellen
|
||||
```bash
|
||||
# Pruefen ob semgrep installiert ist
|
||||
which semgrep || bash install-semgrep.sh
|
||||
```
|
||||
|
||||
### 2. Geaenderte Dateien ermitteln
|
||||
```bash
|
||||
# Untracked und modified files
|
||||
git status --porcelain | grep -E '^\?\?|^ M|^M' | cut -c4-
|
||||
```
|
||||
|
||||
### 3. Security Scan ausfuehren
|
||||
```bash
|
||||
# Mit Auto-Config (empfohlen)
|
||||
semgrep --config=auto --json .
|
||||
|
||||
# Fuer TypeScript/React spezifisch
|
||||
semgrep --config=p/typescript --config=p/react --json .
|
||||
|
||||
# OWASP Top 10
|
||||
semgrep --config=p/owasp-top-ten --json .
|
||||
```
|
||||
|
||||
### 4. Ergebnisse analysieren und fixen
|
||||
```bash
|
||||
# Mit Autofix
|
||||
semgrep --config=auto --autofix .
|
||||
|
||||
# Nur Report ohne Fix
|
||||
semgrep --config=auto --sarif -o results.sarif .
|
||||
```
|
||||
|
||||
## Haeufige Security Issues und Fixes
|
||||
|
||||
### SQL Injection
|
||||
```typescript
|
||||
// SCHLECHT
|
||||
const query = `SELECT * FROM users WHERE id = ${userId}`;
|
||||
|
||||
// GUT
|
||||
const { data } = await supabase.from('users').select('*').eq('id', userId);
|
||||
```
|
||||
|
||||
### XSS (Cross-Site Scripting)
|
||||
```typescript
|
||||
// SCHLECHT
|
||||
<div dangerouslySetInnerHTML={{ __html: userInput }} />
|
||||
|
||||
// GUT
|
||||
<div>{sanitize(userInput)}</div>
|
||||
```
|
||||
|
||||
### Hardcoded Secrets
|
||||
```typescript
|
||||
// SCHLECHT
|
||||
const apiKey = "sk-1234567890";
|
||||
|
||||
// GUT
|
||||
const apiKey = process.env.API_KEY;
|
||||
```
|
||||
|
||||
### Insecure Direct Object Reference
|
||||
```typescript
|
||||
// SCHLECHT - Keine Auth-Pruefung
|
||||
const user = await getUser(req.query.id);
|
||||
|
||||
// GUT - Mit RLS oder Auth-Check
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
const profile = await supabase.from('profiles').select().eq('user_id', user.id);
|
||||
```
|
||||
|
||||
## Report Format
|
||||
|
||||
Nach jedem Scan zeige:
|
||||
|
||||
```markdown
|
||||
## Security Scan Ergebnisse
|
||||
|
||||
**Score**: 85/100
|
||||
|
||||
| Severity | Count |
|
||||
|----------|-------|
|
||||
| Critical | 0 |
|
||||
| High | 1 |
|
||||
| Medium | 3 |
|
||||
| Low | 5 |
|
||||
|
||||
### Gefundene Issues
|
||||
|
||||
1. **[HIGH] Potential XSS** in `components/Comment.tsx:42`
|
||||
- Problem: Unescaped user input
|
||||
- Fix: Verwende DOMPurify oder sanitize-html
|
||||
|
||||
### Automatisch gefixt
|
||||
- 2 Issues wurden automatisch behoben
|
||||
|
||||
### Naechste Schritte
|
||||
- [ ] Issue #1 manuell pruefen
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Immer scannen** nach Code-Aenderungen
|
||||
2. **Autofix nutzen** fuer einfache Issues
|
||||
3. **Kritische Issues** sofort beheben
|
||||
4. **False Positives** in `.semgrepignore` ausschliessen
|
||||
5. **CI/CD Integration** fuer automatische Scans
|
||||
54
.claude/skills/semgrep-security/autofix.sh
Executable file
54
.claude/skills/semgrep-security/autofix.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
# Fuehrt Semgrep Autofix durch
|
||||
|
||||
set -e
|
||||
|
||||
# Farben
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Pruefen ob Semgrep installiert ist
|
||||
if ! command -v semgrep &> /dev/null; then
|
||||
echo -e "${YELLOW}Semgrep nicht gefunden. Installiere...${NC}"
|
||||
bash "$(dirname "$0")/install-semgrep.sh"
|
||||
fi
|
||||
|
||||
# Argumente
|
||||
if [ $# -gt 0 ]; then
|
||||
SCAN_TARGET="$@"
|
||||
else
|
||||
SCAN_TARGET="."
|
||||
fi
|
||||
|
||||
echo "Starte Semgrep Autofix..."
|
||||
echo "========================="
|
||||
echo ""
|
||||
|
||||
# Autofix durchfuehren
|
||||
# Nur Rules mit Autofix-Support
|
||||
semgrep \
|
||||
--config=auto \
|
||||
--autofix \
|
||||
--dryrun \
|
||||
$SCAN_TARGET 2>&1 | head -50
|
||||
|
||||
echo ""
|
||||
read -p "Fixes anwenden? (y/n) " -n 1 -r
|
||||
echo ""
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Wende Fixes an..."
|
||||
semgrep \
|
||||
--config=auto \
|
||||
--autofix \
|
||||
$SCAN_TARGET
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Fixes angewendet!${NC}"
|
||||
echo ""
|
||||
echo "Bitte pruefen Sie die Aenderungen:"
|
||||
echo " git diff"
|
||||
else
|
||||
echo "Autofix abgebrochen."
|
||||
fi
|
||||
86
.claude/skills/semgrep-security/install-semgrep.sh
Executable file
86
.claude/skills/semgrep-security/install-semgrep.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
# Installiert Semgrep basierend auf dem Betriebssystem
|
||||
|
||||
set -e
|
||||
|
||||
echo "Pruefe Semgrep Installation..."
|
||||
|
||||
# Pruefen ob bereits installiert
|
||||
if command -v semgrep &> /dev/null; then
|
||||
echo "Semgrep ist bereits installiert: $(semgrep --version)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Semgrep nicht gefunden. Starte Installation..."
|
||||
|
||||
# OS erkennen
|
||||
OS_TYPE=$(uname -s)
|
||||
|
||||
case "$OS_TYPE" in
|
||||
"Darwin")
|
||||
# macOS
|
||||
echo "macOS erkannt - nutze Homebrew"
|
||||
if command -v brew &> /dev/null; then
|
||||
brew install semgrep
|
||||
else
|
||||
echo "Homebrew nicht gefunden - nutze pip3"
|
||||
pip3 install semgrep
|
||||
fi
|
||||
;;
|
||||
|
||||
"Linux")
|
||||
echo "Linux erkannt"
|
||||
|
||||
# Versuche verschiedene Paketmanager
|
||||
if command -v apt-get &> /dev/null; then
|
||||
echo "Nutze apt-get..."
|
||||
# Semgrep via Python da apt Version oft veraltet
|
||||
pip3 install semgrep
|
||||
|
||||
elif command -v apk &> /dev/null; then
|
||||
echo "Alpine erkannt - nutze pip3"
|
||||
apk add --no-cache python3 py3-pip
|
||||
pip3 install semgrep
|
||||
|
||||
elif command -v yum &> /dev/null; then
|
||||
echo "RHEL/CentOS erkannt - nutze pip3"
|
||||
pip3 install semgrep
|
||||
|
||||
else
|
||||
echo "Nutze pip3 als Fallback"
|
||||
pip3 install semgrep
|
||||
fi
|
||||
;;
|
||||
|
||||
"MINGW"*|"MSYS"*|"CYGWIN"*)
|
||||
# Windows
|
||||
echo "Windows erkannt"
|
||||
if command -v choco &> /dev/null; then
|
||||
choco install semgrep -y
|
||||
elif command -v pip3 &> /dev/null; then
|
||||
pip3 install semgrep
|
||||
elif command -v pip &> /dev/null; then
|
||||
pip install semgrep
|
||||
else
|
||||
echo "Bitte installiere Python und pip: https://www.python.org/downloads/"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unbekanntes OS: $OS_TYPE - nutze pip3"
|
||||
pip3 install semgrep
|
||||
;;
|
||||
esac
|
||||
|
||||
# Verifizieren
|
||||
if command -v semgrep &> /dev/null; then
|
||||
echo ""
|
||||
echo "Installation erfolgreich!"
|
||||
semgrep --version
|
||||
else
|
||||
echo ""
|
||||
echo "Installation fehlgeschlagen."
|
||||
echo "Bitte manuell installieren: https://semgrep.dev/docs/getting-started/"
|
||||
exit 1
|
||||
fi
|
||||
91
.claude/skills/semgrep-security/rules/next-security.yaml
Normal file
91
.claude/skills/semgrep-security/rules/next-security.yaml
Normal file
@@ -0,0 +1,91 @@
|
||||
# Custom Semgrep Rules fuer Next.js Security
|
||||
|
||||
rules:
|
||||
# Verhindere dangerouslySetInnerHTML ohne Sanitization
|
||||
- id: next-xss-dangerous-html
|
||||
patterns:
|
||||
- pattern: dangerouslySetInnerHTML={{ __html: $VAR }}
|
||||
- pattern-not: dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize($VAR) }}
|
||||
- pattern-not: dangerouslySetInnerHTML={{ __html: sanitize($VAR) }}
|
||||
message: "XSS Risiko: Verwende DOMPurify.sanitize() bevor du dangerouslySetInnerHTML nutzt"
|
||||
severity: ERROR
|
||||
languages: [typescript, javascript]
|
||||
|
||||
# Verhindere hardcoded API Keys
|
||||
- id: next-hardcoded-api-key
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$KEY = "sk-..."
|
||||
- pattern: |
|
||||
$KEY = "pk_..."
|
||||
- pattern: |
|
||||
apiKey: "..."
|
||||
- pattern: |
|
||||
api_key = "..."
|
||||
message: "Hardcoded API Key gefunden. Verwende Environment Variables."
|
||||
severity: ERROR
|
||||
languages: [typescript, javascript]
|
||||
|
||||
# Verhindere ungeschuetzte API Routes
|
||||
- id: next-unprotected-api-route
|
||||
patterns:
|
||||
- pattern: |
|
||||
export async function $METHOD(request: NextRequest) {
|
||||
...
|
||||
$DB.$OPERATION(...)
|
||||
...
|
||||
}
|
||||
- pattern-not: |
|
||||
export async function $METHOD(request: NextRequest) {
|
||||
...
|
||||
auth.getUser()
|
||||
...
|
||||
}
|
||||
- pattern-not: |
|
||||
export async function $METHOD(request: NextRequest) {
|
||||
...
|
||||
getSession()
|
||||
...
|
||||
}
|
||||
message: "API Route ohne Authentication. Fuege Auth-Check hinzu."
|
||||
severity: WARNING
|
||||
languages: [typescript]
|
||||
paths:
|
||||
include:
|
||||
- "app/api/**"
|
||||
|
||||
# Verhindere Secrets in Client Components
|
||||
- id: next-secret-in-client
|
||||
patterns:
|
||||
- pattern-inside: |
|
||||
"use client"
|
||||
...
|
||||
- pattern-either:
|
||||
- pattern: process.env.SUPABASE_SERVICE_ROLE_KEY
|
||||
- pattern: process.env.DATABASE_URL
|
||||
- pattern: process.env.$SECRET_KEY
|
||||
message: "Server-only Secret in Client Component. Verschiebe in Server Component oder API Route."
|
||||
severity: ERROR
|
||||
languages: [typescript, javascript]
|
||||
|
||||
# Verhindere eval und new Function
|
||||
- id: next-no-eval
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: eval(...)
|
||||
- pattern: new Function(...)
|
||||
message: "eval() und new Function() sind Sicherheitsrisiken. Finde eine Alternative."
|
||||
severity: ERROR
|
||||
languages: [typescript, javascript]
|
||||
|
||||
# Supabase RLS Check
|
||||
- id: supabase-rls-bypass
|
||||
patterns:
|
||||
- pattern: supabaseAdmin.from($TABLE)
|
||||
- pattern-not-inside: |
|
||||
// RLS bypassed intentionally
|
||||
...
|
||||
message: "supabaseAdmin umgeht RLS. Stelle sicher dass dies beabsichtigt ist."
|
||||
severity: WARNING
|
||||
languages: [typescript, javascript]
|
||||
29
.claude/skills/semgrep-security/scan-changed.sh
Executable file
29
.claude/skills/semgrep-security/scan-changed.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
# Scannt nur geaenderte Dateien (staged + unstaged)
|
||||
|
||||
set -e
|
||||
|
||||
# Farben
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo "Ermittle geaenderte Dateien..."
|
||||
|
||||
# Geaenderte Dateien ermitteln (TypeScript/JavaScript)
|
||||
CHANGED_FILES=$(git status --porcelain 2>/dev/null | \
|
||||
grep -E '\.(ts|tsx|js|jsx)$' | \
|
||||
sed 's/^...//' | \
|
||||
tr '\n' ' ')
|
||||
|
||||
if [ -z "$CHANGED_FILES" ]; then
|
||||
echo -e "${GREEN}Keine geaenderten TypeScript/JavaScript Dateien gefunden.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Geaenderte Dateien:"
|
||||
echo "$CHANGED_FILES" | tr ' ' '\n' | grep -v '^$'
|
||||
echo ""
|
||||
|
||||
# Scan durchfuehren
|
||||
bash "$(dirname "$0")/scan.sh" $CHANGED_FILES
|
||||
89
.claude/skills/semgrep-security/scan.sh
Executable file
89
.claude/skills/semgrep-security/scan.sh
Executable file
@@ -0,0 +1,89 @@
|
||||
#!/bin/bash
|
||||
# Fuehrt Semgrep Security Scan durch
|
||||
|
||||
set -e
|
||||
|
||||
# Farben fuer Output
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Pruefen ob Semgrep installiert ist
|
||||
if ! command -v semgrep &> /dev/null; then
|
||||
echo -e "${YELLOW}Semgrep nicht gefunden. Installiere...${NC}"
|
||||
bash "$(dirname "$0")/install-semgrep.sh"
|
||||
fi
|
||||
|
||||
# Argumente: spezifische Dateien oder alles scannen
|
||||
if [ $# -gt 0 ]; then
|
||||
SCAN_TARGET="$@"
|
||||
echo "Scanne spezifische Dateien: $SCAN_TARGET"
|
||||
else
|
||||
SCAN_TARGET="."
|
||||
echo "Scanne gesamtes Projekt..."
|
||||
fi
|
||||
|
||||
# Temporaere Datei fuer JSON Output
|
||||
RESULT_FILE=$(mktemp)
|
||||
|
||||
# Scan durchfuehren
|
||||
echo ""
|
||||
echo "Starte Security Scan..."
|
||||
echo "========================"
|
||||
|
||||
semgrep \
|
||||
--config=auto \
|
||||
--config=p/security-audit \
|
||||
--config=p/typescript \
|
||||
--json \
|
||||
--output="$RESULT_FILE" \
|
||||
$SCAN_TARGET 2>/dev/null || true
|
||||
|
||||
# Ergebnisse parsen
|
||||
if [ -f "$RESULT_FILE" ]; then
|
||||
# Anzahl der Findings zaehlen
|
||||
TOTAL=$(jq '.results | length' "$RESULT_FILE" 2>/dev/null || echo "0")
|
||||
ERRORS=$(jq '[.results[] | select(.extra.severity == "ERROR")] | length' "$RESULT_FILE" 2>/dev/null || echo "0")
|
||||
WARNINGS=$(jq '[.results[] | select(.extra.severity == "WARNING")] | length' "$RESULT_FILE" 2>/dev/null || echo "0")
|
||||
INFO=$(jq '[.results[] | select(.extra.severity == "INFO")] | length' "$RESULT_FILE" 2>/dev/null || echo "0")
|
||||
|
||||
echo ""
|
||||
echo "========================"
|
||||
echo "Scan Ergebnisse"
|
||||
echo "========================"
|
||||
echo ""
|
||||
|
||||
if [ "$TOTAL" -eq 0 ]; then
|
||||
echo -e "${GREEN}Keine Sicherheitsprobleme gefunden!${NC}"
|
||||
else
|
||||
echo -e "Gefunden: ${RED}$ERRORS Critical/High${NC}, ${YELLOW}$WARNINGS Medium${NC}, $INFO Low"
|
||||
echo ""
|
||||
|
||||
# Details ausgeben
|
||||
echo "Details:"
|
||||
echo "--------"
|
||||
jq -r '.results[] | "[\(.extra.severity)] \(.check_id)\n File: \(.path):\(.start.line)\n Message: \(.extra.message)\n"' "$RESULT_FILE" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Score berechnen
|
||||
SCORE=$((100 - (ERRORS * 10) - (WARNINGS * 3) - (INFO * 1)))
|
||||
if [ $SCORE -lt 0 ]; then SCORE=0; fi
|
||||
|
||||
echo ""
|
||||
echo "========================"
|
||||
echo -e "Security Score: ${GREEN}$SCORE/100${NC}"
|
||||
echo "========================"
|
||||
|
||||
# Cleanup
|
||||
rm -f "$RESULT_FILE"
|
||||
|
||||
# Exit mit Fehler wenn kritische Issues
|
||||
if [ "$ERRORS" -gt 0 ]; then
|
||||
echo ""
|
||||
echo -e "${RED}WARNUNG: Es wurden kritische Sicherheitsprobleme gefunden!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo -e "${GREEN}Scan abgeschlossen - keine Ergebnisdatei erstellt${NC}"
|
||||
fi
|
||||
Reference in New Issue
Block a user