Retour à l'accueil

Routes dynamiques net/http : implémentation DeadDrop

L'article analyse l'implémentation de routes dynamiques et d'authentification par cookie en pur net/http pour le service DeadDrop. Analyse manuelle des chemins, jetons HMAC, architecture use case. Cycle complet avec tests.

net/http : routes dynamiques et auth cookie dans DeadDrop
Advertisement 728x90

Routes dynamiques et authentification par cookies avec net/http : Implémentation de DeadDrop

Poursuivant notre série sur net/http pur, nous implémentons le routage dynamique pour le service DeadDrop. Les utilisateurs pourront consulter des secrets via des liens comme /secret/{id}. Le routeur standard ne prend pas en charge les paramètres de chemin avant Go 1.22, nous écrivons donc notre propre analyseur.

Le gestionnaire est enregistré à /secret/ avec une barre oblique finale — cela capture tous les chemins enfants. Nous extrayons l'ID manuellement depuis 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
}

La fonction vérifie le préfixe, le supprime, et exclut les ID invalides (vides ou contenant /). Cela offre une protection basique contre les requêtes malformées.

Google AdInline article slot

SecretHandler avec injection de dépendances

Nous créons une structure de gestionnaire pour l'injection de dépendances :

type SecretHandler struct {
    // placeholder pour l'injection de dépendances
}

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("Secret demandé avec l'ID : " + id))
}

Enregistrez-le dans router.go : mux.Handle("/secret/", secretHandler). Testez les cas limites :

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

Cas d'utilisation pour récupérer un secret

Définissez la requête et la réponse :

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
}

Logique du cas d'utilisation :

  • Récupérez le secret depuis le stockage
  • Vérifiez l'expiration (time.After()), supprimez ceux expirés
  • Vérifiez le mot de passe via CheckPasswordHash
  • Retournez les données ou une erreur

Authentification par cookies

Pour protéger les téléchargements de fichiers, nous implémentons l'authentification via des cookies. Après une vérification réussie du mot de passe, définissez un cookie de session avec un jeton d'accès chiffré.

  • Avantages : sans état, évolutif, pas de stockage de session
  • Paramètres du cookie : HttpOnly, Secure, SameSite=Strict

Lors d'une requête /download/{id} :

Google AdInline article slot
  • Extrayez l'ID du chemin
  • Lisez le cookie auth_token
  • Décodez et vérifiez le jeton (ID + hachage du mot de passe + nonce)
  • Si valide — servez le fichier

Structure du jeton d'accès

Le jeton est formé comme base64(ID + ":" + hash + ":" + nonce), où :

  • hash = HMAC-SHA256(ID + mot de passe, cléSecrète)
  • nonce — un numéro à usage unique pour protéger contre les attaques par rejeu

Exemple de validation :

func validateDownloadToken(id, token string) bool {
    // décodez le jeton
    // extrayez le hachage et le nonce
    // recalculez le HMAC
    // comparez
    return true // ou false
}

Flux complet du secret

  • Création : POST /create → générez l'ID, hachez le mot de passe, sauvegardez
  • Consultation : GET /secret/{id} → formulaire de saisie du mot de passe
  • Authentification : POST mot de passe → cookie + redirection
  • Téléchargement : GET /download/{id} → vérifiez le cookie → fichier
  • Nettoyage : TTL expiré → suppression

Prototype d'interface : page avec champ de mot de passe, bouton "Ouvrir". Après succès — contenu + lien de fichier.

Tests de routage

| Chemin de test | Attente | Résultat |

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

| /secret/123/ | 404 | 404 |

| /secret/ | 404 | 404 |

| /secret/id/avec/barre | 404 | 404 |

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

Les cas limites couvrent la sécurité de l'analyseur.

Points clés

  • Routes dynamiques : analyse manuelle de r.URL.Path sans routeurs tiers
  • Sécurité : validation de l'ID, vérifications des barres obliques, TTL pour les secrets
  • Authentification : cookie avec jeton HMAC au lieu de sessions
  • Architecture : cas d'utilisation + injection de dépendances, logique propre en dehors des gestionnaires
  • Évolutivité : sans état, prêt pour le clustering

— Editorial Team

Advertisement 728x90

Lire ensuite