SHA256
refactor: drop built-in HTTPS, serve plain HTTP behind reverse proxy
TLS termination belongs to the trusted reverse proxy in front (nginx/caddy/...), not the app. run.py now binds plain HTTP to 127.0.0.1 (HOST/PORT configurable) and the dirty rollback of the reverted self-signed-cert logic was cleaned up. README updated. Verified: all endpoints 200 over HTTP, integrity tests 3/3 passing. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
This commit is contained in:
@@ -8,18 +8,19 @@ Alle Datensätze werden **im Browser** verschlüsselt
|
|||||||
Der Server sieht ausschließlich Chiffretext – auch bei vollständiger
|
Der Server sieht ausschließlich Chiffretext – auch bei vollständiger
|
||||||
Serverkompromittierung bleiben die Inhalte ohne Passphrase vertraulich.
|
Serverkompromittierung bleiben die Inhalte ohne Passphrase vertraulich.
|
||||||
|
|
||||||
## Starten (HTTPS, Dev mit self-signed Zertifikat)
|
## Starten (HTTP; TLS über Reverse Proxy)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -m venv venv
|
python3 -m venv venv
|
||||||
./venv/bin/pip install -r requirements.txt
|
./venv/bin/pip install -r requirements.txt
|
||||||
./venv/bin/python run.py
|
./venv/bin/python run.py
|
||||||
# → https://127.0.0.1:8443
|
# → http://127.0.0.1:5000
|
||||||
```
|
```
|
||||||
|
|
||||||
Ein selbstsigniertes Zertifikat wird bei Bedarf automatisch erzeugt
|
Die App lauscht auf dem lokalen HTTP-Port (default `127.0.0.1:5000`,
|
||||||
(`certs/`). Zertifikatswarnungen im Browser sind in der Entwicklung
|
überschreibbar via `HOST`/`PORT`). Ein vertrauenswürdiger Reverse Proxy
|
||||||
erwartet und zu bestätigen.
|
(nginx, caddy, …) beendet HTTPS und reicht intern an die App weiter.
|
||||||
|
Die App selbst muss von außen nicht erreichbar sein.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ node .e2e.mjs # optional: End-to-End (siehe unten)
|
|||||||
| API | `backend/app.py` | Flask REST API, Validierung nur von Form/Größe, Versions-Konfliktprüfung |
|
| 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 |
|
| 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 |
|
| UI | `backend/static/ui.js` + `index.html`/`style.css` | Tabelle, Erstellen, Bearbeiten, Löschen; Passphrase bleibt im RAM |
|
||||||
| Server | `run.py` | HTTPS (self-signed Dev-Zertifikat), DB-Init |
|
| Server | `run.py` | HTTP intern hinter Reverse Proxy, DB-Init |
|
||||||
|
|
||||||
## Sicherheitsmodell
|
## Sicherheitsmodell
|
||||||
|
|
||||||
@@ -49,7 +50,8 @@ node .e2e.mjs # optional: End-to-End (siehe unten)
|
|||||||
(Replay alter Stände) → `409`, Duplikate → `409`.
|
(Replay alter Stände) → `409`, Duplikate → `409`.
|
||||||
- Klartexte werden clientseitig nie persistiert; beim Sperren/Beenden
|
- Klartexte werden clientseitig nie persistiert; beim Sperren/Beenden
|
||||||
wird der Schlüssel verworfen (`wipeKey`).
|
wird der Schlüssel verworfen (`wipeKey`).
|
||||||
- HTTPS (Dev: self-signed; Prod: eigenes Zertifikat hinterlegen).
|
- HTTPS wird außen vom vertrauenswürdigen **Reverse Proxy** beendet
|
||||||
|
(nginx/caddy/…); die App lauscht nur intern auf HTTP.
|
||||||
|
|
||||||
## Bekannte Grenzen
|
## Bekannte Grenzen
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
"""Dev/Prod entry point. Runs the Flask app, over TLS when certs exist."""
|
"""Entrypoint. Runs the Flask app over plain HTTP on a local port.
|
||||||
|
|
||||||
|
TLS is NOT terminated here: a trusted reverse proxy (nginx/caddy/...)
|
||||||
|
in front handles HTTPS and forwards to this internal HTTP port. The
|
||||||
|
proxy must be the only thing reachable from outside; bind this app to
|
||||||
|
127.0.0.1 (or a private interface) only.
|
||||||
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import ssl
|
|
||||||
|
|
||||||
from backend.app import app
|
from backend.app import app
|
||||||
from backend import storage
|
from backend import storage
|
||||||
@@ -10,16 +15,10 @@ from backend import storage
|
|||||||
def main():
|
def main():
|
||||||
storage.init_db()
|
storage.init_db()
|
||||||
|
|
||||||
cert = os.path.join("certs", "cert.pem")
|
host = os.environ.get("HOST", "127.0.0.1")
|
||||||
key = os.path.join("certs", "key.pem")
|
port = int(os.environ.get("PORT", "5000"))
|
||||||
|
|
||||||
if os.path.exists(cert) and os.path.exists(key):
|
app.run(host=host, port=port)
|
||||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
|
||||||
context.load_cert_chain(cert, key)
|
|
||||||
app.run(host="127.0.0.1", port=8443, ssl_context=context)
|
|
||||||
else:
|
|
||||||
print("WARNING: no certs/ found, running WITHOUT TLS (dev only!).")
|
|
||||||
app.run(host="127.0.0.1", port=5000)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user