Zpět na domů

Dynamické trasy net/http: implementace DeadDrop

Článek rozebírá implementaci dynamických tras a autentizace cookie v čistém net/http pro službu DeadDrop. Ruční parsování cest, HMAC tokeny, architektura use case. Plný cyklus s testy.

net/http: dynamické trasy a cookie auth v DeadDrop
Advertisement 728x90

Dynamické trasy a cookie autentizace v net/http: implementace DeadDrop

V pokračování cyklu o čistém net/http implementujeme dynamické směrování pro službu DeadDrop. Uživatelé budou moci prohlížet tajemství pomocí odkazů ve tvaru /secret/{id}. Standardní mux nepodporuje parametry cest až do Go 1.22, proto píšeme vlastní parser.

Ošetřovač se registruje na /secret/ s koncovým lomítkem – to zachytí všechny podřízené cesty. ID extrahujeme ručně z r.URL.Path.

func extractIDFromPath(path string) (string, bool) {
    const prefix = "/secret/"

    if !strings.HasPrefix(path, prefix) {
        return "", false
    }

    id := strings.TrimPrefix(path, prefix)
    if id == "" || strings.Contains(id, "/") {
        return "", false
    }

    return id, true
}

Funkce kontroluje prefix, ořízne ho a vyloučí neplatná ID (prázdná nebo s /). Toto je základní ochrana proti nesprávným požadavkům.

Google AdInline article slot

Ošetřovač SecretHandler s DI

Vytvoříme strukturu-ošetřovač pro vkládání závislostí:

type SecretHandler struct {
    // zástupný symbol pro DI
}

func NewSecretHandler() *SecretHandler {
    return &SecretHandler{}
}

func (h *SecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    id, ok := url.ExtractIDFromPath(r.URL.Path)
    if !ok {
        http.NotFound(w, r)
        return
    }
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("Požadováno tajemství s ID: " + id))
}

Zaregistrujeme v router.go: mux.Handle("/secret/", secretHandler). Otestujeme hraniční případy:

  • /secret/12345/ → 404
  • /secret/ → 404
  • /secret/axQ/233 → 404
  • /secret/ad31H234 → OK s ID

Use Case pro získání tajemství

Definujeme požadavek a odpověď:

Google AdInline article slot
type GetSecretRequest struct {
    ID       string
    Password string
}

type GetSecretResponse struct {
    ID        string
    Message   string
    FileName  string
    FileExt   string
    HasFile   bool
    ExpiresAt time.Time
}

Logika use case:

  • Extrahujeme tajemství z úložiště
  • Kontrolujeme dobu platnosti (time.After()), odstraníme vypršená
  • Ověříme heslo pomocí CheckPasswordHash
  • Vrátíme data nebo chybu

Cookie autentizace

Pro ochranu stahování souborů zavádíme autentizaci pomocí cookies. Po úspěšném ověření hesla nastavíme sezení cookie se zašifrovaným přístupovým tokenem.

  • Výhody: bezstavové, škálovatelné, žádné ukládání sezení
  • Parametry cookie: HttpOnly, Secure, SameSite=Strict

Při požadavku /download/{id}:

Google AdInline article slot
  • Extrahujeme ID z cesty
  • Přečteme cookie auth_token
  • Dekódujeme a ověříme token (ID + hash hesla + nonce)
  • Při platnosti – poskytneme soubor

Struktura přístupového tokenu

Token je vytvořen jako base64(ID + ":" + hash + ":" + nonce), kde:

  • hash = HMAC-SHA256(ID + password, secretKey)
  • nonce – jednorázové číslo pro ochranu proti replay útokům

Příklad validace:

func validateDownloadToken(id, token string) bool {
    // dekódujeme token
    // extrahujeme hash a nonce
    // přepočítáme HMAC
    // porovnáme
    return true // nebo false
}

Úplný cyklus práce s tajemstvím

  • Vytvoření: POST /create → vygenerujeme ID, zahashujeme heslo, uložíme
  • Prohlížení: GET /secret/{id} → formulář pro zadání hesla
  • Autentizace: POST heslo → cookie + přesměrování
  • Stahování: GET /download/{id} → kontrola cookie → soubor
  • Vyčištění: TTL vypršelo → odstranění

Prototyp UI: stránka s polem pro heslo, tlačítko "Otevřít". Po úspěchu – obsah + odkaz na soubor.

Testování směrování

| Testovací cesta | Očekávání | Výsledek |

|---------------|----------|-----------|

| /secret/123/ | 404 | 404 |

| /secret/ | 404 | 404 |

| /secret/id/with/slash | 404 | 404 |

| /secret/valid123 | OK: "ID: valid123" | OK |

Hraniční případy pokrývají bezpečnost parseru.

Co je důležité

  • Dynamické trasy: ruční parsování r.URL.Path bez externích routerů
  • Bezpečnost: validace ID, kontrola lomítek, TTL pro tajemství
  • Autentizace: cookie s HMAC tokenem místo sezení
  • Architektura: use case + DI, čistá logika mimo handler
  • Škálovatelnost: bezstavové, připraveno pro cluster

— Editorial Team

Advertisement 728x90

Číst dál