SHA256
Setup screen shares the unlock panel look; README gains an "Erster Start (UX)" section explaining first visit vs returning visit behaviour. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
81 lines
3.4 KiB
Markdown
81 lines
3.4 KiB
Markdown
# crushdb – verschlüsselte Datensätze zwischen Personen
|
||
|
||
Sichere Datenbank für Transaktionen zwischen zwei Personen
|
||
(Person A, Person B, Timestamp-Start, Timestamp-Ende, Aktion).
|
||
|
||
Alle Datensätze werden **im Browser** verschlüsselt
|
||
(XChaCha20-Poly1305, Schlüsselableitung per Argon2id aus der Passphrase).
|
||
Der Server sieht ausschließlich Chiffretext – auch bei vollständiger
|
||
Serverkompromittierung bleiben die Inhalte ohne Passphrase vertraulich.
|
||
|
||
## Erster Start (UX)
|
||
|
||
- **Beim ersten Besuch** (Datenbank leer): Die App zeigt "Willkommen" und
|
||
fragt zweimal nach einer neuen Passphrase (mindestens 8 Zeichen).
|
||
Diese schützt ab sofort alle Datensätze – es gibt keine Zurücksetzung.
|
||
- **Bei weiteren Besuchen**: Die App bittet einmal um die bekannte
|
||
Passphrase ("Entsperren").
|
||
- Der Server speichert niemals die Passphrase selbst, nur verschlüsselte
|
||
Datensätze.
|
||
|
||
## Starten (HTTP; TLS über Reverse Proxy)
|
||
|
||
```bash
|
||
python3 -m venv venv
|
||
./venv/bin/pip install -r requirements.txt
|
||
./venv/bin/python run.py
|
||
# → http://127.0.0.1:8085
|
||
```
|
||
|
||
Die App lauscht auf dem lokalen HTTP-Port (default `127.0.0.1:8085`,
|
||
überschreibbar via `HOST`/`PORT`). Ein vertrauenswürdiger Reverse Proxy
|
||
(nginx, caddy, …) beendet HTTPS und reicht intern an die App weiter.
|
||
Die App selbst muss von außen nicht erreichbar sein.
|
||
|
||
### Per systemd laufen lassen
|
||
|
||
Ein fertiges Unit-File liegt in `deploy/crushdb.service` (Reinheit:
|
||
nur `instance/` schreibbar, keine Capabilities, Restart on failure).
|
||
Nach dem Kopieren nach `/etc/systemd/system/` und `daemon-reload`
|
||
startet `systemctl enable --now crushdb` die App dauerhaft.
|
||
|
||
## Tests
|
||
|
||
```bash
|
||
./venv/bin/python -m pytest backend/test_integrity.py -v # Integrität/Replay
|
||
node .e2e.mjs # optional: End-to-End (siehe unten)
|
||
```
|
||
|
||
## Architektur
|
||
|
||
| Komponente |Datei | Aufgabe |
|
||
|---|---|---|
|
||
| Speicher | `backend/storage.py` | SQLite, speichert nur Chiffretext (uuid, ciphertext, nonce, salt, version) |
|
||
| API | `backend/app.py` | Flask REST API, Validierung nur von Form/Größe, Versions-Konfliktprüfung |
|
||
| Krypto (Client) | `backend/static/crypto.js` | Argon2id-KDF + XChaCha20-Poly1305, uuid+salt als AEAD-AAD gebunden |
|
||
| UI | `backend/static/ui.js` + `index.html`/`style.css` | Tabelle, Erstellen, Bearbeiten, Löschen; Passphrase bleibt im RAM |
|
||
| Server | `run.py` | HTTP intern hinter Reverse Proxy, DB-Init |
|
||
|
||
## Sicherheitsmodell
|
||
|
||
- Passphrase → Argon2id (t=2, m=16 MiB) → 256-Bit-Sitzungsschlüssel,
|
||
ausschließlich im Browser/im Arbeitsspeicher; niemals am Server.
|
||
- Jeder Datensatz: eigene zufällige 16-Byte-Salt + 24-Byte-Nonce.
|
||
uuid + salt sind als AEAD-Associated-Data gebunden – Vertauschen oder
|
||
Um-Salten wird beim Entschlüsseln sicher erkannt.
|
||
- Monotoner Versionszähler pro Datensatz: veraltete Updates/Deletes
|
||
(Replay alter Stände) → `409`, Duplikate → `409`.
|
||
- Klartexte werden clientseitig nie persistiert; beim Sperren/Beenden
|
||
wird der Schlüssel verworfen (`wipeKey`).
|
||
- HTTPS wird außen vom vertrauenswürdigen **Reverse Proxy** beendet
|
||
(nginx/caddy/…); die App lauscht nur intern auf HTTP.
|
||
|
||
## Bekannte Grenzen
|
||
|
||
- Datenverlust (Löschen/Überschreiben) durch Angreifer bleibt möglich –
|
||
Vertraulichkeit ist geschützt, Verfügbarkeit nicht.
|
||
- Backups der SQLite-Datei enthalten ausschließlich Chiffretext.
|
||
- Backups des Passphrasen-Verlusts = Datenverlust (by design).
|
||
|
||
Siehe `spezification.txt` für die Anforderungen.
|