security(sharing): Freigabelink prüft die Prüfsumme, Gruppenordner teilbar
Beim Lesen von internal/sharing fiel eine ungleiche Zusage auf: Der angemeldete Download prüft seit dem 12.09. die SHA-256-Summe beim Ausliefern und lässt die Verbindung fallen, wenn sie nicht stimmt. Der öffentliche Freigabelink lief durch ein blankes io.Copy – ungeprüft. Ausgerechnet der Weg nach draussen. Wer die Datei angemeldet holt, ist der Eigentümer und merkt, wenn etwas kaputt ist; wer einen Link bekommt, merkt es nicht. In CLAUDE.md steht das unter „nicht verhandelbar": beim Upload berechnen, beim Download verifizieren. Die Regel galt an einer von zwei Stellen. Die Mechanik liegt jetzt in files/verified.go und wird von beiden gerufen. Nachgewiesen mit gekipptem Bit auf der Platte: Über den Freigabelink kommt die Datei ebenfalls nicht mehr vollständig an. Gruppenordner: Create übergab user.ID statt des aufgelösten Prinzipals – eine Datei im Gruppenordner liess sich nicht verlinken, auch nicht vom Mitglied. Marcs Entscheidung: Das soll gehen, der Empfänger sieht ohnehin nur die Datei, nie den Ordner darum. Verlangt wird Schreibrecht: Einen Link zu erzeugen heisst, die Datei öffentlich zu machen; wer sie nur geliehen lesen darf, soll sie nicht weiterreichen können (403). expires_in_hours hatte keine Obergrenze. time.Duration rechnet in Nanosekunden; ab etwa 2,6 Mio Stunden läuft int64 über, die Dauer wird negativ, und der Link ist abgelaufen in dem Moment, in dem er entsteht – ohne Fehlermeldung. Jetzt zehn Jahre, darüber 400. Dazu X-Content-Type-Options: nosniff, das der angemeldete Weg längst setzt. Sechs Go-Tests für internal/sharing, unter Mutation nachgewiesen: Eigentümerprüfung entfernt, Ablaufprüfung entfernt und Token verkürzt machen jeweils genau den zugehörigen Test rot. Selbsttests erweitert: sharing 24 → 31 Prüfungen, pruefsumme 14 → 16. Geprüft: go build/vet sauber, alle Go-Pakete grün, 241 Prüfungen der sieben Selbsttest-Suiten grün, 48 Vitest-Tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a7528d7365
commit
6fab2388ca
9 files changed
+628
-74
No files matched your search
+70
@@ -1562,6 +1562,76 @@ bleibt `node` (schnell); wer ein DOM braucht, schreibt
|
||||
|
||||
---
|
||||
|
||||
## Freigabelinks: Prüfsumme, Gruppenordner, Grenzen (25.09.2026)
|
||||
|
||||
Beim Lesen von `internal/sharing` fiel eine ungleiche Zusage auf: Der
|
||||
**angemeldete** Download prüft seit dem 12.09. die SHA-256-Summe beim
|
||||
Ausliefern und lässt die Verbindung fallen, wenn sie nicht stimmt. Der
|
||||
**öffentliche Freigabelink** lief durch ein blankes `io.Copy` – ungeprüft.
|
||||
|
||||
Ausgerechnet der Weg nach draussen. Wer die Datei angemeldet holt, ist der
|
||||
Eigentümer und merkt, wenn etwas kaputt ist; wer einen Link bekommt, merkt es
|
||||
nicht. In CLAUDE.md steht das unter "nicht verhandelbar": beim Upload
|
||||
berechnen, **beim Download verifizieren**. Die Regel galt an einer von zwei
|
||||
Stellen.
|
||||
|
||||
Die Prüfmechanik liegt jetzt in `files/verified.go` (`ServeVerified`) und wird
|
||||
von beiden gerufen, statt ein zweites Mal geschrieben zu werden.
|
||||
|
||||
- [x] Bit auf der Platte kippen, Datei ueber den Freigabelink holen -> kommt
|
||||
**nicht** vollstaendig an. Mit 200-KB- und 900-Byte-Datei geprueft, der
|
||||
Selbsttest macht das jetzt fuer beide Wege.
|
||||
|
||||
### Gruppenordner lassen sich verlinken
|
||||
|
||||
`Create` uebergab `user.ID` statt des aufgeloesten Prinzipals. Eine Datei in
|
||||
einem Gruppenordner liess sich damit nicht verlinken – auch nicht von einem
|
||||
Mitglied, das sie sehen und herunterladen darf. Die Antwort lautete "file not
|
||||
found".
|
||||
|
||||
Marcs Entscheidung: Das soll gehen, der Empfaenger sieht ohnehin nur die
|
||||
Datei, nie den Ordner darum.
|
||||
|
||||
**Schreibrecht, nicht nur Leserecht.** Einen Link zu erzeugen heisst, die
|
||||
Datei oeffentlich zu machen. Wer sie nur geliehen lesen darf, soll sie nicht
|
||||
weiterreichen koennen -> 403.
|
||||
|
||||
- [x] Datei im Gruppenordner verlinken -> 201, Link funktioniert oeffentlich
|
||||
- [x] Nur-Lese-Freigabe -> eigener Freigabelink wird mit 403 abgelehnt
|
||||
|
||||
### Zwei Kleinigkeiten
|
||||
|
||||
**`expires_in_hours` hatte keine Obergrenze.** `time.Duration` rechnet in
|
||||
Nanosekunden; ab etwa 2,6 Millionen Stunden laeuft `int64` ueber, die Dauer
|
||||
wird **negativ**, und der Link ist in dem Moment abgelaufen, in dem er
|
||||
entsteht – ohne Fehlermeldung. Jetzt zehn Jahre Obergrenze mit klarer
|
||||
Ablehnung darueber.
|
||||
|
||||
**`X-Content-Type-Options: nosniff`** fehlte. `attachment` traegt die
|
||||
Hauptlast, aber der angemeldete Weg setzt beides.
|
||||
|
||||
- [x] `expires_in_hours: 9000000000` -> 400 mit Begruendung
|
||||
- [x] `expires_in_hours: 24` -> 201
|
||||
- [x] Oeffentlicher Download setzt nosniff
|
||||
|
||||
### Go-Tests fuer `internal/sharing`
|
||||
|
||||
Sechs Testfunktionen, unter Mutation nachgewiesen:
|
||||
|
||||
| Mutation | wird rot |
|
||||
|---|---|
|
||||
| Eigentuemerpruefung beim Loeschen entfernt | `TestFremderLinkLaesstSichNichtLoeschen` |
|
||||
| Ablaufpruefung entfernt | `TestAbgelaufenerLinkGiltNichtMehr` |
|
||||
| Token auf 6 Byte verkuerzt | `TestTokenIstNichtZuErraten` |
|
||||
|
||||
Dazu: Die Liste zeigt nur eigene Links, der Passwort-Hash verlaesst den
|
||||
Speicher nur beim Tokenabruf (dort wird er gebraucht), der Zaehler zaehlt.
|
||||
|
||||
> **Falle beim Erweitern des Selbsttests:** `GET /api/v1/auth/me` dreht den
|
||||
> CSRF-Token weiter. Wer ihn zwischendurch ruft und den alten weiterbenutzt,
|
||||
> bekommt 403 – genau das ist mir passiert, obwohl es seit dem 12.09. hier
|
||||
> steht.
|
||||
|
||||
## Ein Wächter für die Sprache (24.09.2026)
|
||||
|
||||
Sechs Tage nach der Übersetzung fielen beim Nachsehen **fünf Reste** auf:
|
||||
|
||||
Reference in new issue
Block a user