fix(docs): Master-Passwort interaktiv hashen, nicht auf der Kommandozeile
Meine Anleitung schrieb `htpasswd -bnBC 12 "" PASSWORT` — und lieferte 401, obwohl Hash und Konfiguration nachweislich stimmten. Die Ursache liegt vor dem Hashen: Das Passwort steht dort ungeschuetzt in einer Kommandozeile, und die Shell fasst es an. `ge$heim` wird zu `ge`, `ge heim` zu `geheim`; gehasht wird etwas anderes als das, was man spaeter eintippt. Richtig ist `htpasswd -nBC 12 ''` ohne -b: Es fragt zweimal nach, das Passwort geht nie durch eine Shell und landet nicht in der History. Dazu eine direkte Probe (htpasswd -v gegen den gespeicherten Hash), weil der Fehler wie ein Konfigurationsfehler aussieht — alles Pruefbare stimmt, nur der Vergleich schlaegt fehl. Vier Stellen: deploy-backend.sh, beide READMEs, MasterPasswordProperties. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0ed757a80a
commit
78901793f0
@@ -292,6 +292,10 @@ Configuration lives in the git-ignored `.env` (template `.env.example`):
|
|||||||
- **The master password never leaves the server.** It goes into
|
- **The master password never leaves the server.** It goes into
|
||||||
`<BACKEND_DIR>/env` (mode 600), which the deploy creates empty on the first
|
`<BACKEND_DIR>/env` (mode 600), which the deploy creates empty on the first
|
||||||
run. Until a hash is in it, the document list stays locked — deliberately.
|
run. Until a hash is in it, the document list stays locked — deliberately.
|
||||||
|
Generate it **interactively** (`htpasswd -nBC 12 ''`, no `-b`): a password on
|
||||||
|
a command line lands in the shell history, and the shell mangles it on the
|
||||||
|
way — `ge$heim` becomes `ge`. What gets hashed is then not what you type
|
||||||
|
later, and the server answers 401 while everything looks right.
|
||||||
- **Memory is the scarce resource on that host**, not CPU. The JVM flags are
|
- **Memory is the scarce resource on that host**, not CPU. The JVM flags are
|
||||||
measured, not guessed: `-Xmx192m -Xms48m` plus heap free ratios lands at
|
measured, not guessed: `-Xmx192m -Xms48m` plus heap free ratios lands at
|
||||||
~174 MB RSS, where the defaults take 291 MB. See
|
~174 MB RSS, where the defaults take 291 MB. See
|
||||||
|
|||||||
+7
-1
@@ -171,9 +171,15 @@ auffindbar — das Zugriffsmodell „unerratbarer Link" wäre hinfällig. Dieser
|
|||||||
Endpunkt verlangt deshalb HTTP Basic mit dem Benutzer `werkbaum`:
|
Endpunkt verlangt deshalb HTTP Basic mit dem Benutzer `werkbaum`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export WERKBAUM_MASTER_PASSWORD_HASH="{bcrypt}$(htpasswd -bnBC 12 "" geheim | tr -d ':\n')"
|
export WERKBAUM_MASTER_PASSWORD_HASH="{bcrypt}$(htpasswd -nBC 12 '' | tr -d ':\n')"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Ohne `-b`, also mit Eingabeaufforderung.** Ein Passwort auf der Kommandozeile
|
||||||
|
landet in der Shell-History — und schlimmer: Die Shell fasst es vorher an.
|
||||||
|
`ge$heim` wird zu `ge`, `ge heim` zu `geheim`. Gehasht wird dann etwas anderes
|
||||||
|
als das, was man später eintippt, und der Server antwortet mit 401, obwohl
|
||||||
|
alles richtig aussieht.
|
||||||
|
|
||||||
- **Ohne gesetzten Hash ist die Liste gesperrt** (401), nicht offen. Ein
|
- **Ohne gesetzten Hash ist die Liste gesperrt** (401), nicht offen. Ein
|
||||||
vergessener Konfigurationsschritt darf nichts preisgeben; beim Start warnt
|
vergessener Konfigurationsschritt darf nichts preisgeben; beim Start warnt
|
||||||
das Log.
|
das Log.
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ data class MasterPasswordProperties(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash **mit Verfahrens-Präfix**, in Produktion `{bcrypt}$2a$…`
|
* Hash **mit Verfahrens-Präfix**, in Produktion `{bcrypt}$2a$…`
|
||||||
* (z. B. `htpasswd -bnBC 12 "" geheim | tr -d ':\n'`, davor `{bcrypt}`).
|
* Erzeugt mit `htpasswd -nBC 12 '' | tr -d ':\n'`, davor `{bcrypt}`.
|
||||||
|
* Bewusst **ohne** `-b`: Ein Passwort auf der Kommandozeile fasst die
|
||||||
|
* Shell an (`ge${'$'}heim` wird zu `ge`), und gehasht würde etwas anderes
|
||||||
|
* als das, was später eingetippt wird.
|
||||||
*/
|
*/
|
||||||
val hash: String = "",
|
val hash: String = "",
|
||||||
|
|
||||||
|
|||||||
@@ -6192,6 +6192,23 @@ Securitys `DelegatingPasswordEncoder`). So steht in der Konfiguration, womit
|
|||||||
gehasht wurde, ein Wechsel des Verfahrens bricht nichts — und die Tests dürfen
|
gehasht wurde, ein Wechsel des Verfahrens bricht nichts — und die Tests dürfen
|
||||||
`{noop}` benutzen, ohne dass dafür eine zweite Code-Bahn nötig wäre.
|
`{noop}` benutzen, ohne dass dafür eine zweite Code-Bahn nötig wäre.
|
||||||
|
|
||||||
|
**Nachtrag beim ersten Einrichten: der Hash wird interaktiv erzeugt, nie mit
|
||||||
|
dem Passwort auf der Kommandozeile.** Die erste Anleitung schrieb
|
||||||
|
`htpasswd -bnBC 12 "" PASSWORT` — und lieferte prompt ein 401, obwohl Hash und
|
||||||
|
Konfiguration nachweislich in Ordnung waren (68 Zeichen, `{bcrypt}`, drei `$`,
|
||||||
|
im Prozess angekommen). Die Ursache liegt vor dem Hashen: Das Passwort steht
|
||||||
|
dort ungeschützt in einer Kommandozeile, und die Shell fasst es an —
|
||||||
|
`ge$heim` wird zu `ge`, `ge heim` zu `geheim`. Gehasht wird dann etwas anderes
|
||||||
|
als das, was man später eintippt.
|
||||||
|
|
||||||
|
Richtig ist `htpasswd -nBC 12 ''` **ohne `-b`**: Es fragt zweimal nach, das
|
||||||
|
Passwort geht nie durch eine Shell und landet nicht in der History. Der Fehler
|
||||||
|
ist besonders unangenehm, weil er wie ein Konfigurationsfehler aussieht — alles
|
||||||
|
Prüfbare stimmt, nur der Vergleich schlägt fehl. Zum Auseinanderhalten gehört
|
||||||
|
deshalb eine direkte Probe in die Anleitung: `htpasswd -v` gegen den
|
||||||
|
gespeicherten Hash sagt in einem Schritt, ob Hash und Passwort zueinander
|
||||||
|
passen, ohne den Dienst zu befragen.
|
||||||
|
|
||||||
**Die neue Laufzeit-Abhängigkeit** (`spring-boot-starter-security`) ist in D76
|
**Die neue Laufzeit-Abhängigkeit** (`spring-boot-starter-security`) ist in D76
|
||||||
ausdrücklich vorgesehen („geprüft über Spring Security") und damit von der
|
ausdrücklich vorgesehen („geprüft über Spring Security") und damit von der
|
||||||
Rückfragepflicht der Wurzel-CLAUDE.md gedeckt. Sie ist zugleich der Platz für
|
Rückfragepflicht der Wurzel-CLAUDE.md gedeckt. Sie ist zugleich der Platz für
|
||||||
|
|||||||
@@ -151,9 +151,19 @@ if [ ! -f "$DIR/env" ]; then
|
|||||||
cat > "$DIR/env" <<'ENV'
|
cat > "$DIR/env" <<'ENV'
|
||||||
# Werkbaum-Backend — Umgebung des Dienstes. Modus 600, nie im Repository.
|
# Werkbaum-Backend — Umgebung des Dienstes. Modus 600, nie im Repository.
|
||||||
#
|
#
|
||||||
# Hash MIT Verfahrens-Praefix, z. B.:
|
# Hash MIT Verfahrens-Praefix. Erzeugen - INTERAKTIV, damit das Passwort weder
|
||||||
# WERKBAUM_MASTER_PASSWORD_HASH={bcrypt}$(htpasswd -bnBC 12 "" geheim | tr -d ':\n')
|
# in der Shell-History landet noch von der Shell veraendert wird:
|
||||||
# Solange er leer ist, bleibt GET /api/v1/documents gesperrt (D76-Nachtrag 6).
|
#
|
||||||
|
# umask 077
|
||||||
|
# printf 'WERKBAUM_MASTER_PASSWORD_HASH={bcrypt}%s\n' \
|
||||||
|
# "$(htpasswd -nBC 12 '' | tr -d ':\n')" > ~/opt/werkbaum/env
|
||||||
|
#
|
||||||
|
# Pruefen, ob Hash und Passwort zueinander passen:
|
||||||
|
# printf 'werkbaum:%s\n' "$(sed 's/^[^=]*={bcrypt}//' ~/opt/werkbaum/env)" > /tmp/chk
|
||||||
|
# htpasswd -v /tmp/chk werkbaum; rm -f /tmp/chk
|
||||||
|
#
|
||||||
|
# Solange der Hash leer ist, bleibt GET /api/v1/documents gesperrt
|
||||||
|
# (D76-Nachtrag 6).
|
||||||
WERKBAUM_MASTER_PASSWORD_HASH=
|
WERKBAUM_MASTER_PASSWORD_HASH=
|
||||||
ENV
|
ENV
|
||||||
chmod 600 "$DIR/env"
|
chmod 600 "$DIR/env"
|
||||||
|
|||||||
Reference in New Issue
Block a user