Stage 0: Repository und Architekturgrundlage
- Pyproject.toml mit FastAPI, Pydantic v2, SQLAlchemy, httpx, asyncio, BeautifulSoup4, selectolax, trafilatura, uvicorn, pytest-asyncio - Multi-stage Dockerfile (Python 3.12-slim, Non-Root-User nsct) - docker-compose.yml (nsct-api + postgres + optional searxng) - .env.example mit allen Config-Parametern - Config-System: AppSettings mit LLMConfig, VisionConfig, AudioConfig, DatabaseConfig — komplett aus Environment, keine Hardcodes - Strukturiertes Logging mit research_id/llm_request_id Tracking - Pydantic v2 Schemas: SearchQuery, Source, Claim, EvidenceRelation, CitationEdge, ResearchReport - SQLAlchemy 2.0 Declarative Models + async Engine Factory - SSRF-Schutz: URL-Validation, IP-Blocklist (RFC1918, Cloud Metadata, file://, ftp://) - Provider-Interfaces: LLMProvider, VisionProvider, AudioProvider, SearchProvider, ContentFetcher als ABCs - Health-Endpoints: /health, /ready (LLM-Connect-Test), /providers - FastAPI App mit CORS, lifespan (LLM Pre-Flight) - CLI-Stub mit Entry-Points: nsct, nsct-core, nsct-api - 6 Test-Cases: /health, /ready, /providers + No-Secrets-Test - Vollständige Dokumentation: README, ARCHITECTURE, SECURITY, METHODOLOGY, API, DEPLOYMENT - .gitignore (Python, Docker, IDE, .env)
This commit is contained in:
105
SECURITY.md
Normal file
105
SECURITY.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# NSCT — Sicherheitsgrundsätze
|
||||
|
||||
## 1. Grundprinzip
|
||||
|
||||
NSCT verarbeitet **untrusted input** von überall im Web. Jede externe Quelle
|
||||
kann versuchen, die Integrität des Systems zu kompromittieren. Alle
|
||||
Sicherheitsmaßnahmen folgen dem "zero trust" Prinzip.
|
||||
|
||||
## 2. Control Plane vs. Evidence Plane
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ CONTROL PLANE │
|
||||
│ (vertrauenswürdige, interne Daten) │
|
||||
│ │
|
||||
│ • Konfiguration (Environment Variables) │
|
||||
│ • Strukturierter Prompt (LLM Instruktionen) │
|
||||
│ • Normierte Claims (bereinigt, de-biased) │
|
||||
│ • EvidenceRelations (Vergleichsergebnisse) │
|
||||
└──────────────┬──────────────────────────────────────────┘
|
||||
│
|
||||
│ LLM verarbeitet NUR strukturierte Daten
|
||||
│
|
||||
┌──────────────▼──────────────────────────────────────────┐
|
||||
│ EVIDENCE PLANE │
|
||||
│ (untrusted, externe Daten) │
|
||||
│ │
|
||||
│ • Roh-Webcontent (HTML, Text) │
|
||||
│ • Search-Provider-Ergebnisse │
|
||||
│ • Extrahierte Claims (roh, unverarbeitet) │
|
||||
│ • Audio/Vision-Rohdaten │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Regel:** Webcontent wechselt niemals direkt die Grenze von Evidence Plane
|
||||
in die Control Plane als Prompt-Text.
|
||||
|
||||
## 3. SSRF-Schutz
|
||||
|
||||
Jede outbound-HTTP-Anfrage muss durch `nsct/security/policy.py`:
|
||||
|
||||
1. **Schema-Check:** Nur `http://` und `https://` erlaubt
|
||||
2. **IP-Blocklist:**
|
||||
- `127.0.0.0/8` — Loopback
|
||||
- `10.0.0.0/8` — Private Class A
|
||||
- `172.16.0.0/12` — Private Class B
|
||||
- `192.168.0.0/16` — Private Class C
|
||||
- `169.254.0.0/16` — Link-local / Link-local
|
||||
- `192.0.0.0/24` — IETF Protocol Assignments
|
||||
- `100.64.0.0/10` — Shared Address Space
|
||||
- `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24` — TEST-NET
|
||||
3. **Metadata-Endpunkte:** Cloud-Instance-Metadata (`169.254.169.254`, etc.)
|
||||
4. **Schemata:** `file://`, `ftp://`, `gopher://`, `ldap://`, `data://` blockiert
|
||||
|
||||
## 4. Prompt-Isolation
|
||||
|
||||
Der LLM darf **niemals** rohen Webcontent als Teil des Prompts sehen. Der
|
||||
einzige Weg, Webcontent für den LLM verfügbar zu machen, ist über strukturierte
|
||||
Daten:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": {
|
||||
"url": "https://example.com",
|
||||
"domain": "example.com",
|
||||
"title": "Titel",
|
||||
"author": "Autor",
|
||||
"content_type": "news",
|
||||
"language": "de"
|
||||
},
|
||||
"claims": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"normalized_claim": "De-biased claim text",
|
||||
"claim_type": "factual",
|
||||
"confidence": 0.95
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Der LLM sieht **nur** dieses JSON — nie den HTML/Raw-Text.
|
||||
|
||||
## 5. Untrusted Data Handling
|
||||
|
||||
| Quelle | Risiko | Schutzmaßnahme |
|
||||
|--------|--------|---------------|
|
||||
| Search Provider | Fake-Scores, Manipulation | Score != Evidence-Ranking; nur als Eingabe |
|
||||
| Web Content | XSS, Prompt-Injection, SSRF | HTML-Extraktion → Text, strikte Schema-Validierung |
|
||||
| LLM Output | Halluzination, Bias | Claims mit confidence scoring; keine single-source truth |
|
||||
| Audio/Vision | Manipulierte Inputs | Content-Type-Validierung; Größ Limits |
|
||||
|
||||
## 6. Docker-Sicherheit
|
||||
|
||||
- **Non-Root-User:** `nsct` (UID 1000)
|
||||
- **Read-Only-Filesystem:** `read_only: true` wo möglich
|
||||
- **Dropped Capabilities:** `cap_drop: [ALL]`
|
||||
- **No Secrets in Image:** `.env` wird nicht gebuildet
|
||||
- **Resource Limits:** Memory und CPU begrenzt pro Container
|
||||
|
||||
## 7. Compliance
|
||||
|
||||
- Keine Speicherung von personenbezogenen Daten über die Quellen-Metadaten hinaus
|
||||
- Claims und Evidence Relations werden nur so lange gespeichert wie nötig
|
||||
- Alle Daten sind exportierbar und löschbar (SQLAlchemy cascade)
|
||||
Reference in New Issue
Block a user