Audit-Siegel: Platzhalter zaehlt nicht als Schluessel + Betriebsfalle dokumentiert
.env.example zeigt jetzt wie bei den anderen Secrets einen sichtbaren Platzhalter an der Variablen statt eines leeren Werts - verstaendlicher, aber mit Schutz dagegen: ein nicht ersetzter Platzhalter (enthaelt < oder >, oder beginnt mit change/dein/your/hier) gilt NICHT als Schluessel. Sonst wuerde mit einem oeffentlich im Repository stehenden Wert gesiegelt, was Sicherheit vortaeuscht. Das Backend warnt in dem Fall im Log und laesst das Siegel aus. Verifiziert: mit Platzhalter geschriebene Zeile bleibt hashVersion 2. Dabei aufgefallen und dokumentiert: Wird das Siegel nach Aktivierung wieder abgeschaltet (Schluessel fehlt, z. B. beim Rebuild verloren), sind die in dieser Zeit entstandenen Eintraege ungesiegelt und werden beanstandet, sobald der Schluessel zurueck ist. Das ist Absicht - ein ungesiegelter Eintrag inmitten gesiegelter ist von einer Faelschung nicht zu unterscheiden. Warnung in README und .env.example. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -365,6 +365,19 @@ ungesiegelt. Das ist kein Fehler, sondern liegt in der Natur der Sache: Ein
|
|||||||
Siegel kann man nur beim Anlegen vergeben, nicht nachträglich. Je früher du
|
Siegel kann man nur beim Anlegen vergeben, nicht nachträglich. Je früher du
|
||||||
den Schlüssel setzt, desto größer der geschützte Zeitraum.
|
den Schlüssel setzt, desto größer der geschützte Zeitraum.
|
||||||
|
|
||||||
|
> ⚠️ **Einmal gesetzt, nicht wieder abschalten.** Fehlt der Schlüssel später
|
||||||
|
> (z. B. weil er beim Container-Rebuild aus der `.env` verlorenging), läuft die
|
||||||
|
> Anwendung normal weiter – aber die in dieser Zeit entstandenen Einträge sind
|
||||||
|
> ungesiegelt und werden von der Prüfung **beanstandet**, sobald der Schlüssel
|
||||||
|
> wieder da ist. Das ist Absicht: Ein ungesiegelter Eintrag inmitten
|
||||||
|
> gesiegelter ist von einer Fälschung nicht zu unterscheiden. Nimm den
|
||||||
|
> Schlüssel deshalb in deine Deploy-Checkliste auf.
|
||||||
|
|
||||||
|
Ein noch nicht ersetzter Platzhalter (`<hier-eigenen-wert-eintragen>`) zählt
|
||||||
|
bewusst **nicht** als Schlüssel – sonst würde mit einem öffentlich bekannten
|
||||||
|
Wert gesiegelt. Das Backend schreibt in diesem Fall eine Warnung ins Log und
|
||||||
|
lässt das Siegel aus.
|
||||||
|
|
||||||
**Häufige Fragen**
|
**Häufige Fragen**
|
||||||
|
|
||||||
| Frage | Antwort |
|
| Frage | Antwort |
|
||||||
|
|||||||
+13
-7
@@ -53,6 +53,13 @@ NODE_ENV=development
|
|||||||
# dadurch KEINE Fehlalarme. Rueckwirkend siegeln geht nicht - je frueher
|
# dadurch KEINE Fehlalarme. Rueckwirkend siegeln geht nicht - je frueher
|
||||||
# gesetzt, desto groesser der geschuetzte Zeitraum.
|
# gesetzt, desto groesser der geschuetzte Zeitraum.
|
||||||
#
|
#
|
||||||
|
# ACHTUNG: einmal gesetzt, nicht wieder abschalten.
|
||||||
|
# Fehlt der Schluessel spaeter (z. B. beim Container-Rebuild verlorengegangen),
|
||||||
|
# laeuft alles weiter - aber die in dieser Zeit entstandenen Eintraege sind
|
||||||
|
# ungesiegelt und werden beanstandet, sobald der Schluessel wieder da ist.
|
||||||
|
# Ein ungesiegelter Eintrag inmitten gesiegelter ist von einer Faelschung
|
||||||
|
# nicht zu unterscheiden. Also: in die Deploy-Checkliste aufnehmen.
|
||||||
|
#
|
||||||
# Was passiert, wenn ich ihn verliere?
|
# Was passiert, wenn ich ihn verliere?
|
||||||
# Laesst du das Feld LEER, gelten die gesiegelten Eintraege als
|
# Laesst du das Feld LEER, gelten die gesiegelten Eintraege als
|
||||||
# "nicht pruefbar" - NICHT als gefaelscht, also kein Fehlalarm. Der
|
# "nicht pruefbar" - NICHT als gefaelscht, also kein Fehlalarm. Der
|
||||||
@@ -62,11 +69,11 @@ NODE_ENV=development
|
|||||||
# ein falscher Schluessel ist von einer Faelschung nicht zu unterscheiden.
|
# ein falscher Schluessel ist von einer Faelschung nicht zu unterscheiden.
|
||||||
# Deshalb: Schluessel sichern, so wie ein Passwort.
|
# Deshalb: Schluessel sichern, so wie ein Passwort.
|
||||||
#
|
#
|
||||||
# Hier steht bewusst KEIN Beispielwert: leer = Siegel aus (nichts faellt aus).
|
# Eigenen Wert erzeugen mit: openssl rand -hex 32
|
||||||
# Ein Beispielwert waere gefaehrlicher als keiner - er stuende oeffentlich im
|
# Der Platzhalter unten zaehlt NICHT als Schluessel - laesst du ihn stehen,
|
||||||
# Repository, und jeder koennte damit Eintraege siegeln. Trage deinen eigenen,
|
# bleibt das Siegel aus (es wird also nicht versehentlich mit einem oeffentlich
|
||||||
# selbst erzeugten Wert ein:
|
# bekannten Wert gesiegelt). Leer lassen ist ebenfalls in Ordnung.
|
||||||
AUDIT_HMAC_KEY=
|
AUDIT_HMAC_KEY=<hier-eigenen-wert-eintragen>
|
||||||
|
|
||||||
# Frueher verwendete Schluessel - beim Wechsel hier eintragen.
|
# Frueher verwendete Schluessel - beim Wechsel hier eintragen.
|
||||||
# Moechtest du den Schluessel oben austauschen (z. B. weil du vermutest,
|
# Moechtest du den Schluessel oben austauschen (z. B. weil du vermutest,
|
||||||
@@ -83,8 +90,7 @@ AUDIT_HMAC_KEY=
|
|||||||
# Mehrfach gewechselt? Mehrere Schluessel kommagetrennt, juengster zuerst:
|
# Mehrfach gewechselt? Mehrere Schluessel kommagetrennt, juengster zuerst:
|
||||||
# AUDIT_HMAC_KEY_OLD=<vorheriger>,<davor>,<ganz alter>
|
# AUDIT_HMAC_KEY_OLD=<vorheriger>,<davor>,<ganz alter>
|
||||||
#
|
#
|
||||||
# Beim ersten Einrichten bleibt das Feld leer - es wird erst beim Wechsel
|
# Beim ersten Einrichten leer lassen - erst beim Schluesselwechsel noetig.
|
||||||
# gebraucht.
|
|
||||||
AUDIT_HMAC_KEY_OLD=
|
AUDIT_HMAC_KEY_OLD=
|
||||||
|
|
||||||
# --- Technisch (fuer Entwickler/Admins) ---------------------------------
|
# --- Technisch (fuer Entwickler/Admins) ---------------------------------
|
||||||
|
|||||||
@@ -222,9 +222,32 @@ export interface AuditHashV2Input {
|
|||||||
* `AUDIT_HMAC_KEY_OLD` erlaubt einen Schluesselwechsel ohne Rehash – bei der
|
* `AUDIT_HMAC_KEY_OLD` erlaubt einen Schluesselwechsel ohne Rehash – bei der
|
||||||
* Pruefung wird zusaetzlich gegen den alten Schluessel getestet.
|
* Pruefung wird zusaetzlich gegen den alten Schluessel getestet.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Ein nicht ersetzter Platzhalter aus `.env.example` (z. B.
|
||||||
|
* `<hier-eigenen-wert-eintragen>`) darf NICHT als Schluessel gelten. Sonst
|
||||||
|
* wuerde mit einem oeffentlich im Repository stehenden Wert gesiegelt – das
|
||||||
|
* waere schlechter als gar kein Siegel, weil es Sicherheit vortaeuscht.
|
||||||
|
*/
|
||||||
|
function istPlatzhalter(k: string): boolean {
|
||||||
|
return k.includes('<') || k.includes('>') || /^(change|dein|your|hier)/i.test(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
let platzhalterGemeldet = false;
|
||||||
|
|
||||||
function auditHmacKey(): string | null {
|
function auditHmacKey(): string | null {
|
||||||
const k = process.env.AUDIT_HMAC_KEY;
|
const k = process.env.AUDIT_HMAC_KEY?.trim();
|
||||||
return k && k.trim().length > 0 ? k : null;
|
if (!k) return null;
|
||||||
|
if (istPlatzhalter(k)) {
|
||||||
|
if (!platzhalterGemeldet) {
|
||||||
|
platzhalterGemeldet = true;
|
||||||
|
console.warn(
|
||||||
|
'[Audit] AUDIT_HMAC_KEY enthält noch den Platzhalter aus .env.example – ' +
|
||||||
|
'das Audit-Siegel bleibt deaktiviert. Eigenen Wert erzeugen: openssl rand -hex 32',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -236,7 +259,7 @@ function auditHmacKeysOld(): string[] {
|
|||||||
return (process.env.AUDIT_HMAC_KEY_OLD || '')
|
return (process.env.AUDIT_HMAC_KEY_OLD || '')
|
||||||
.split(',')
|
.split(',')
|
||||||
.map((k) => k.trim())
|
.map((k) => k.trim())
|
||||||
.filter((k) => k.length > 0);
|
.filter((k) => k.length > 0 && !istPlatzhalter(k));
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateHashV3(data: AuditHashV2Input, key: string): string {
|
function generateHashV3(data: AuditHashV2Input, key: string): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user