Sicherheit & Robustheit härten
- SQLite-DSN: busy_timeout(5000) + WAL + foreign_keys gegen SQLITE_BUSY - uid ist nie 0 mehr (0 = Sentinel für gelöscht/anonym), Retry bei Kollision - scanEntries gibt Scan-Fehler zurück statt Zeilen still zu überspringen - Session-timeout serverseitig auf 30 Tage gedeckelt (clientgesteuert) - Bild-Upload: Dimensionen vor Decode prüfen (Decompression-Bomb-Schutz) - Secure-Cookie via TLS-Erkennung (r.TLS / X-Forwarded-Proto) - Rate-Limit (httprate, 20/min/IP) auf Login & Registrierung - Vote nur auf existierende Beiträge (keine Waisen-Votes) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,6 @@ import (
|
||||
)
|
||||
|
||||
func createUser(username, password string) error {
|
||||
uid := int64(rand.IntN(99999999))
|
||||
now := time.Now().Unix()
|
||||
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
@@ -20,11 +19,22 @@ func createUser(username, password string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec(
|
||||
`INSERT INTO user (uid, created_at, username, password) VALUES (?, ?, ?, ?)`,
|
||||
uid, now, username, hash,
|
||||
)
|
||||
return err
|
||||
// uid ist nie 0: 0 ist Sentinel für "gelöscht"/"anonym" (siehe handleDeleteEntry,
|
||||
// uidFromContext). Bei der seltenen UNIQUE-Kollision auf uid neu würfeln.
|
||||
var lastErr error
|
||||
for i := 0; i < 5; i++ {
|
||||
uid := int64(rand.IntN(99999999)) + 1
|
||||
_, lastErr = db.Exec(
|
||||
`INSERT INTO user (uid, created_at, username, password) VALUES (?, ?, ?, ?)`,
|
||||
uid, now, username, hash,
|
||||
)
|
||||
if lastErr == nil {
|
||||
return nil
|
||||
}
|
||||
// username ist ebenfalls UNIQUE und wird vom Aufrufer vorab geprüft;
|
||||
// eine Kollision hier kann also nur die uid sein -> erneut versuchen.
|
||||
}
|
||||
return lastErr
|
||||
}
|
||||
|
||||
// idFromUsername liefert die interne id oder 0, wenn der Nutzer nicht existiert.
|
||||
@@ -169,11 +179,14 @@ func handleUserDelete(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "session",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
Expires: time.Unix(0, 0),
|
||||
MaxAge: -1,
|
||||
Name: "session",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
Expires: time.Unix(0, 0),
|
||||
MaxAge: -1,
|
||||
HttpOnly: true,
|
||||
Secure: isHTTPS(r),
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user