HIGH session fixationfibercockroachdb

Session Fixation in Fiber with Cockroachdb

Session Fixation in Fiber with Cockroachdb — how this specific combination creates or exposes the vulnerability

Session fixation occurs when an application assigns a user a session identifier before authentication and does not regenerate it after login. In a Fiber application using Cockroachdb as the session store, this typically happens when session IDs are created early—often via a cookie set before login—and then persisted in Cockroachdb without being rotated post-authentication.

With Cockroachdb, the session record is stored in a distributed SQL table keyed by the session ID. If the client supplies the pre-auth session ID and the server reuses that same ID after login, the attacker can craft a URL with a known session value (e.g., ?sessionid=attackerchosen) and trick a victim into authenticating under that ID. Because Cockroachdb retains the session row, the attacker can later use the same ID to hijack the authenticated session, provided the session data is not properly invalidated or rotated.

The risk is compounded if:

  • The session cookie is created before login with a predictable or non-rotated ID.
  • Session rows in Cockroachdb are not invalidated on privilege change (e.g., elevation to authenticated).
  • Concurrent session controls are absent, allowing the same session ID to be used from multiple locations without invalidation.

In a black-box scan, middleBrick tests for session fixation by observing whether authentication changes the session identifier and whether prior session data remains accessible. For Fiber apps with Cockroachdb, findings often highlight missing session rotation after login and overly permissive session lookup queries that do not enforce proper ownership checks.

Cockroachdb-Specific Remediation in Fiber — concrete code fixes

Remediation centers on ensuring a new, cryptographically random session ID is issued after successful authentication and that the old Cockroachdb session row is invalidated. Below is a secure pattern using fiber and cockroachdb.

// main.go
package main

import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/jackc/pgx/v5/pgxpool"
)

type Session struct {
	ID        string    \`json:"id\"`
	UserID    string    \`json:"user_id\"`
	ExpiresAt time.Time \`json:"expires_at\"`
}

func main() {
	ctx := context.Background()
	connPool, err := pgxpool.New(ctx, "postgresql://username:password@host:26257/sessiondb?sslmode=require")
	if err != nil {
		log.Fatalf("Unable to connect to Cockroachdb: %v", err)
	}
	defer connPool.Close()

	app := fiber.New()

	app.Post("/login", func(c *fiber.Ctx) error {
		var creds struct {
			Email    string `json:"email"`
			Password string `json:"password"`
		}
		if err := c.BodyParser(&creds); err != nil {
			return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid request"})
		}

		// Validate credentials against users table (omitted for brevity)
		userID, err := authenticateUser(ctx, connPool, creds.Email, creds.Password)
		if err != nil || userID == "" {
			return c.Status(http.StatusUnauthorized).JSON(fiber.Map{"error": "invalid credentials"})
		}

		// Invalidate any pre-existing session for this user (important for fixation prevention)
		if err := invalidateUserSessions(ctx, connPool, userID); err != nil {
			return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "unable to clear existing sessions"})
		}

		// Create a new, random session ID after authentication
		newSessionID, err := generateSecureSessionID()
		if err != nil {
			return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "session generation failed"})
		}

		session := Session{
			ID:        newSessionID,
			UserID:    userID,
			ExpiresAt: time.Now().Add(24 * time.Hour),
		}

		// Store the new session in Cockroachdb
		if _, err := connPool.Exec(ctx, `
			INSERT INTO sessions (id, user_id, expires_at) 
			VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING`, 
			session.ID, session.UserID, session.ExpiresAt); err != nil {
			return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "unable to create session"})
		}

		// Set secure cookie with the new session ID
		c.Cookie(&fiber.Cookie{
			Name:     "session_id",
			Value:    session.ID,
			Expires:  session.ExpiresAt,
			HTTPOnly: true,
			Secure:   true,
			SameSite: fiber.CookieSameSiteStrictMode,
		})

		return c.JSON(fiber.Map{"message": "login successful"})
	})

	app.Listen(":3000")
}

func generateSecureSessionID() (string, error) {
	bytes := make([]byte, 32)
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}
	return hex.EncodeToString(bytes), nil
}

func authenticateUser(ctx context.Context, pool *pgxpool.Pool, email, password string) (string, error) {
	var userID string
	row := pool.QueryRow(ctx, "SELECT id FROM users WHERE email = $1 AND password_hash = crypt($2, password_hash) LIMIT 1", email, password)
	err := row.Scan(&userID)
	if err != nil {
		return "", err
	}
	return userID, nil
}

func invalidateUserSessions(ctx context.Context, pool *pgxpool.Pool, userID string) error {
	_, err := pool.Exec(ctx, "DELETE FROM sessions WHERE user_id = $1", userID)
	return err
}

Key points specific to Cockroachdb:

  • Use ON CONFLICT (id) DO NOTHING to avoid race conditions when inserting the new session, leveraging Cockroachdb’s strong consistency for conditional inserts.
  • Invalidate all prior sessions for the user before issuing the new ID to prevent fixation via lingering rows.
  • Ensure session lookup queries in handlers include user ownership checks (e.g., SELECT ... FROM sessions WHERE id = $1 AND user_id = $2) to avoid horizontal privilege escalation.

middleBrick scans can help detect missing session rotation and overly permissive session queries in unauthenticated sweeps, providing prioritized findings with remediation guidance.

Frequently Asked Questions

Can an attacker exploit session fixation if the session ID is stored in Cockroachdb but never rotated after login?
Yes. If the session ID issued before authentication is reused after login and not regenerated, an attacker can force a victim to authenticate under a known ID and later hijack the session using the same ID stored in Cockroachdb.
Does using the free tier of middleBrick provide session fixation detection for Fiber + Cockroachdb applications?
Yes. The free tier allows 3 scans per month and will surface session fixation findings when an unauthenticated scan detects that the session identifier is not rotated after authentication, along with related Cockroachdb session handling issues.