Mehrschichtige Analyse — Detaillierte Spezifikation
Ziel
Übergang von einer einschichtigen Analyse (ein Modus pro Rule) zu einer mehrschichtigen Analyse, bei der jede Datei durch 3 unabhängige Strategien untersucht wird. Die Ergebnisse werden abgeglichen, um Findings mit hohem Vertrauensgrad und einer für Menschen überprüfbaren Beweiskette zu erzeugen.
Aktuelle Architektur (einschichtig)
Heute verwendet jede Rule EINEN Modus:
Rule sql_injection_fstring
→ regex-Modus: sucht nach ".execute(f""
→ Treffer? → Finding (Confidence 80, fest)
→ Kein Treffer? → Nichts
Probleme:
- Wenn das Pattern zu eng ist, wird die Schwachstelle übersehen (False Negative)
- Wenn das Pattern zu breit ist, wird Rauschen erkannt (False Positive)
- Kein Beweis des Datenflusses (der Entwickler sieht "SQL injection", aber nicht WARUM)
- Die Confidence ist fest (80 oder 95), nicht auf reale Beweise gestützt
Vorgeschlagene Architektur (mehrschichtig)
Für jede Datei laufen 3 Schichten parallel:
┌─────────────────┐
│ Quelldatei │
└────────┬────────┘
│
┌──────────────┼──────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Schicht 1 │ │ Schicht 2 │ │ Schicht 3 │
│ Pattern │ │ Taint │ │ Context │
│ matching │ │ analysis │ │ analysis │
└──────┬─────┘ └──────┬─────┘ └──────┬─────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────┐
│ Beweis-Fusionierer │
│ │
│ Verknüpft die Ergebnisse der 3 Schichten│
│ Berechnet die tatsächliche Confidence. │
│ Erstellt die Beweiskette. │
└────────────────┬────────────────────────┘
│
▼
┌───────────────┐
│ Finding │
│ + Beweise │
│ + Confidence │
└───────────────┘
Schicht 1: Pattern matching (vorhanden, verbessert)
Was sie tut
Sucht nach syntaktischen Patterns im Code (Text oder regex). Es ist die heutige Schicht — schnell, mit breiter Abdeckung.
Was sie liefert
{
"layer": "pattern",
"rule_key": "sql_injection_fstring",
"file": "src/db.py",
"line": 42,
"code": "cursor.execute(f\"SELECT * FROM users WHERE id = {user_id}\")",
"evidence": "Pattern '.execute(f\"' trifft in Zeile 42"
}
Confidence allein: 65 %
Ein Pattern-Treffer allein ist ein Signal, kein Beweis. Das Pattern kann auch sicheren Code treffen (z. B. einen Test, einen Kommentar oder einen Dokumentations-String).
Schicht 2: Taint analysis (vorhanden, angereichert)
Was sie tut
Verfolgt den Datenfluss von einer nicht vertrauenswürdigen Source (HTTP-Eingabe, CLI, Datei) bis zu einem gefährlichen Sink (execute, open, system).
Was sie liefert
{
"layer": "taint",
"rule_key": "taint_sqli",
"file": "src/db.py",
"flow": {
"source": {
"line": 12,
"code": "user_id = request.args.get('id')",
"kind": "http"
},
"propagation": [
{"line": 15, "code": "user_id = int(user_id) if safe else user_id"},
{"line": 38, "code": "query = f\"SELECT * FROM users WHERE id = {user_id}\""}
],
"sink": {
"line": 42,
"code": "cursor.execute(query)",
"type": "sql_execute"
},
"sanitizers_found": false
},
"evidence": "HTTP-Daten (request.args) ohne Sanitizer bis cursor.execute() propagiert"
}
Confidence allein: 85 %
Ein Taint-Flow ist ein starker Beweis — er zeigt den vollständigen Pfad. Er kann jedoch ein False Positive sein, wenn der Sanitizer in einer indirekt aufgerufenen Funktion liegt (außerhalb der Datei).
Schicht 3: Context analysis (neu)
Was sie tut
Analysiert den Kontext der Datei, um die Findings der Schichten 1 und 2 zu bestätigen oder zu widerlegen. Beantwortet Fragen wie:
-
Verwendet die Datei einen ORM (SQLAlchemy, Django ORM)? Wenn ja, ist eine SQL-Injection weniger wahrscheinlich.
-
Importiert die Datei ein Sanitization-Framework?
- Ist die Datei ein Test, ein Mock, eine Fixture? Wenn ja, ignorieren.
- Verarbeitet die Datei HTTP-Anfragen (Routes, Handler)?
- Enthält die Datei Eingabevalidierungen (Schemas, Validators)?
Was sie liefert
{
"layer": "context",
"file": "src/db.py",
"signals": {
"is_test_file": false,
"has_orm": false,
"has_raw_sql": true,
"has_http_handler": true,
"has_input_validation": false,
"has_sanitizer": false,
"framework": "flask"
},
"evidence": "Flask-Datei mit Roh-SQL, kein ORM, keine Eingabevalidierung"
}
Erkannte Kontext-Signale
Die Kontextschicht stützt sich auf eine Reihe von Prüfungen auf Dateiebene, darunter:
- Erkennung von Test/Mock/Fixture-Dateien (Dateiname enthält
test_,_test.,mock,fixture,spec.) - ORM vorhanden (SQLAlchemy, Django ORM, Tortoise, Peewee, Prisma usw.)
- Roh-SQL (
SELECT,INSERT,UPDATE,DELETE) - HTTP-Handler (Flask
@app.route, FastAPI@router.*, Django Views usw.) - Eingabevalidierung (Pydantic, Marshmallow, Cerberus, WTForms, Django Forms usw.)
- Sanitizer vorhanden (Bleach,
html.escape, MarkupSafe, parametrierte Queries usw.)
Beweis-Fusionierer
Berechnung der Confidence
Die endgültige Confidence ist kein Mittelwert — sie ist eine Berechnung auf Grundlage unabhängiger Beweise:
Confidence = Basis + Bonus_Taint + Bonus_Context - Strafen
Konkrete Fälle:
Pattern allein, kein Kontext:
65 % (schwaches Signal, möglicher False Positive)
Pattern + bestätigender Kontext (Roh-SQL, kein ORM, HTTP-Handler):
65 % + 15 % = 80 %
Pattern + Taint-Flow (Source → Sink bestätigt):
65 % + 25 % = 90 %
Pattern + Taint + Kontext (dreifache Bestätigung):
65 % + 25 % + 10 % = 95 % (nahezu sicher)
Pattern + WIDERSPRECHENDER Kontext (ORM vorhanden, Testdatei):
65 % - 30 % = 35 % (wahrscheinlich False Positive → aus dem Bericht entfernt)
Fusionsregeln
1. Wenn die Kontextschicht eine Testdatei erkennt → Finding ENTFERNEN
(Testdateien enthalten absichtlich verwundbaren Code)
2. Wenn die Taint-Schicht den Fluss bestätigt → Confidence ERHÖHEN
und die Beweiskette zum Finding HINZUFÜGEN
3. Wenn die Kontextschicht widerspricht (ORM vorhanden, Sanitizer gefunden) →
Confidence VERRINGERN. Wenn < 40 % → Finding ENTFERNEN
4. Wenn zwei verschiedene Rules dieselbe Schwachstelle an derselben Stelle erkennen →
in einem einzigen Finding mit der höchsten Confidence ZUSAMMENFÜHREN
5. Wenn der Taint-Flow mehrere Dateien durchquert → das Label
"cross-file" HINZUFÜGEN und die Confidence um 5 % ERHÖHEN
Beweiskette im Bericht
Was der Entwickler heute sieht
[HIGH] SQL Injection (f-string) — src/db.py:42
Risk: An attacker can inject malicious SQL...
Solution: Use parameterized queries.
Kein Kontext. Der Entwickler muss selbst herausfinden, warum dies ein Problem ist.
Was der Entwickler mit der mehrschichtigen Analyse sehen würde
[HIGH] SQL Injection (f-string) — src/db.py:42
Confidence: 95 % (pattern + taint + context)
Beweise:
1. Source (Zeile 12):
user_id = request.args.get('id')
→ Nicht vertrauenswürdige HTTP-Daten (kind: http)
2. Propagation (Zeile 38):
query = f"SELECT * FROM users WHERE id = {user_id}"
→ Variable per f-string in eine SQL-Abfrage eingefügt
3. Sink (Zeile 42):
cursor.execute(query)
→ Ausführung der Abfrage ohne Parametrisierung
4. Kontext:
- Flask-Datei mit HTTP-Handler (@app.route)
- Roh-SQL (kein ORM)
- Keine Eingabevalidierung erkannt
- Kein Sanitizer erkannt
Solution: Use parameterized queries.
Playbook: 3 Schritte (Diagnose → Korrektur → Überprüfung)
References: CWE-89, OWASP A03:2021, ISO A.8.28
Der Entwickler kann jeden Schritt des Beweises überprüfen. Wenn er glaubt, dass es sich um einen False Positive handelt, weiß er genau, was zu prüfen ist.
Auswirkung auf False Positives
Die Kontextschicht reduziert False Positives drastisch:
| Situation | Heute | Mehrschichtig |
|---|---|---|
| Pattern in einer Testdatei | Finding (FP) | Entfernt (is_test_file) |
| Pattern in einer Datei mit ORM | Finding (FP) | Confidence 35 % → entfernt |
| Pattern + bestätigter Taint | Finding (80 %) | Finding (95 %) |
| Pattern in einem Kommentar/String | Finding (FP) | Confidence 35 % → entfernt |
Schätzung auf dem aktuellen Benchmark
| Metrik | Aktuell | Mehrschichtig (geschätzt) |
|---|---|---|
| Precision | 81 % | 93 %+ (Kontext filtert FPs) |
| Recall | 99 % | 99 % (gleiche Abdeckung) |
| F1-Score | 89 % | 96 %+ |
Was dies NICHT löst
Die mehrschichtige Analyse verbessert die Qualität der bestehenden Erkennungen. Sie kann Folgendes nicht erkennen:
-
Reine Logikfehler (z. B. IDOR Lunary CVE-2024-1625, bei dem das Problem ein fehlendes WHERE in einer Abfrage ist — kein syntaktisches Pattern)
-
Schwachstellen in Abhängigkeiten (durch pip-audit abgedeckt, nicht durch SAST)
- Schwachstellen in kompiliertem oder verschleiertem Code
Für diese Fälle lauten die Lösungen:
- IDOR: dedizierte Rule "CRUD ohne ownership check" (Rule 4 von BountyBench)
- Abhängigkeiten: pip-audit/npm-audit-Scan (bereits implementiert)
- Kompilierter Code: außerhalb des SAST-Scopes