Guía Completa de Cookies en Go

Las cookies son fragmentos de información enviados desde el servidor hacia el cliente, almacenados como archivos de texto en el dispositivo del cliente. En cada solicitud subsequente, el navegador incluye estos datos, permitiendo al servidor mantener un registro del estado del cliente.

Propósito de las Cookies

Solucionar el problema de la independencia entre solicitudes HTTP. Debido a que HTTP 1.x es un protocolo sin estado, cada solicitud funciona de manera completamente autónoma. Aunque session también podría resolver esto, nos enfocaremos exclusivamente en las cookies.

Proceso de Solución con Cookies

Una respuesta HTTP que establece una cookie se ve así:

Content-Length: 13
Content-Type: text/plain; charset=utf-8
Date: Sat, 21 Aug 2021 14:18:41 GMT
Set-Cookie: token=abc123

El navegador detecta el encabezado Set-Cookie y guarda esa información. En solicitudes posteriores, incluye la cookie en el encabezado de la petición:

Host: localhost:8080
Cookie: token=abc123

Atributos de las Cookies

Las cookies poseen varios atributos: Nombre, Valor, Dominio, Ruta, Expiración/Max-Age, Tamaño, HTTPOnly, Secure.

Descripción de Atributos

1. Nombre y Valor (Name & Value)

El Nombre identifica la cookie y permite al servidor recuperarla específicamente. El Valor contiene los datos, usualmente utilizado como clave para buscar información en el servidor.

2. Dominio y Ruta (Domain & Path)

Dominio especifica qué dominios pueden acceder a la cookie. Por ejemplo, si se establece en .example.com, tanto sub1.example.com como sub2.example.com podrán leerla.
Ruta delimita las rutas dentro del dominio que pueden acceder. Si path=/admin, solo /admin y sus subdirectorios (/admin/dashboard) podrán leer la cookie.

3. Expiración/Max-Age

Define el tiempo de vida. Si no se especifica, dura hasta que se cierre la sesión del navegador. Con un valor específico, expira automáticamente al alcanzar esa fecha.

4. Tamaño (Size)

Representa la cantidad de caracteres en nombre+valor. Por ejemplo, id=666 tiene Size=5.

5. HTTPOnly

Si es true, la cookie solo viaja en encabezados HTTP, no siendo accesible mdeiante document.cookie desde JavaScript.
Propósito de seguridad: Prevenir ataques XSS que roben cookies.

6. Secure

Indica si la cookie solo puede transmitirse por HTTPS. Es un marcador binario sin valores adicionales.

Cookies en Go

La estructura Cookie en Go:

type Cookie struct {
    Name       string    // Nombre de la cookie
    Value      string    // Valor
    
    Path       string    // Ruta opcional
    Domain     string    // Dominio opcional
    Expires    time.Time // Fecha de expiración opcional
    RawExpires string    // Solo para lectura
    
    // MaxAge=0: sin atributo Max-Age
    // MaxAge<0: eliminar cookie ahora (equivalente a Max-Age: 0)
    // MaxAge>0: Max-Age presente en segundos
    MaxAge     int
    Secure     bool
    HttpOnly   bool
    SameSite   SameSite
    Raw        string
    Unparsed   []string   // Pares atributo-valor sin procesar
}

Implementación en Código

Estableciendo Cookies

package main

import (
    "fmt"
    "net/http"
    "time"
)

func configureRoutes() {
    http.HandleFunc("/crear", crearCookie)
    http.HandleFunc("/mostrar", mostrarCookies)
}

func crearCookie(w http.ResponseWriter, r *http.Request) {
    // Cookie básica
    c1 := &http.Cookie{
        Name:     "sesion_usuario",
        Value:    "abc123xyz",
        Path:     "/",
        Expires:  time.Now().Add(24 * time.Hour),
        HttpOnly: true,
        Secure:   false,
    }
    http.SetCookie(w, c1)
    
    // Cookie adicional
    c2 := &http.Cookie{
        Name:   "preferencia_idioma",
        Value:  "es",
        MaxAge: 3600, // 1 hora
    }
    http.SetCookie(w, c2)
    
    fmt.Fprintf(w, "Cookies establecidas correctamente")
}

func mostrarCookies(w http.ResponseWriter, r *http.Request) {
    cookies := r.Cookies()
    fmt.Fprintf(w, "Cookies recibidas: %d\n", len(cookies))
    
    for _, cookie := range cookies {
        fmt.Fprintf(w, "- %s: %s\n", cookie.Name, cookie.Value)
    }
}

func main() {
    configureRoutes()
    fmt.Println("Servidor iniciado en :8080")
    http.ListenAndServe(":8080", nil)
}

Leyendo Cookies

Go ofrece dos métodos principales:

// Obtener todas las cookies
cookies := r.Cookies()

// Obtener cookie específica
sesion, err := r.Cookie("sesion_usuario")
if err != nil {
    // Cookie no encontrada
    fmt.Fprintf(w, "Sesión no iniciada")
} else {
    fmt.Fprintf(w, "Usuario: %s", sesion.Value)
}

Aplicaciones Prácticas

Notificaciones de Uso Único

func mostrarNotificacion(w http.ResponseWriter, r *http.Request) {
    notificacion, err := r.Cookie("mensaje_temporal")
    if err != nil {
        fmt.Fprintf(w, "No hay mensajes nuevos")
        return
    }
    
    // Mostrar mensaje y eliminar cookie
    fmt.Fprintf(w, "Mensaje: %s", notificacion.Value)
    
    // Marcar para eliminación
    notificacion.MaxAge = -1
    http.SetCookie(w, notificacion)
}

Características de las Cookies

Ventajas

  • No consumen recursos del servidor (se almacenan en el cliente)
  • Permiten configurar reglas de expiración flexibles

Desventajas

  • Aumentan el tráfico (se envían en cada petición HTTP)
  • Transmisión en texto claro (vulnerable sin HTTPS)
  • Limitación de tamaño (~4KB)
  • No comparten entre navegadores diferentes
  • Vulnerables a ataques XSS si no se usa HttpOnly

Mejores Prácticas de Seguridad

  • Configurar HttpOnly=true siempre que sea posible
  • Usar Secure=true con HTTPS
  • Establecer SameSite appropriately
  • Definir Path y Domain específicos
  • Implementar expiración adecuada con MaxAge/Expires
  • Validar cookies del lado del servidor con datos del cliente

Inspección de Cookies en Chrome

  1. Navegar a chrome://settings/siteData
  2. Buscar el dominio específico
  3. Inspeccionar los atributos de cada cookie

Nota: El atributo "Scripts access" indica si JavaScript puede leer la cookie (HttpOnly=false).

Etiquetas: Go Cookies HTTP seguridad-web golang

Publicado el 8-15 22:09