HIGH replay attackfiberjwt tokens

Replay Attack in Fiber with Jwt Tokens

Replay Attack in Fiber with Jwt Tokens — how this specific combination creates or exposes the vulnerability

A replay attack occurs when an attacker intercepts a valid JWT issued by an authentication endpoint in a Fiber application and retransmits it to gain unauthorized access. Because JWTs are often designed for stateless validation, they typically carry an expiration (exp) and may include a not-before (nbf) claim, but they do not automatically prevent reuse within the valid time window. In Fiber, if an API route only verifies the signature and claims (such as issuer, audience, and expiration) without additional protections, an intercepted token can be replayed against the same or another endpoint to perform actions as the original user.

The vulnerability is specific to the combination of JWT usage and Fiber routing patterns. For example, consider a login route that returns a signed JWT and an order-creation route that accepts that token. If the token lacks a per-request identifier or a mechanism to detect reuse, an attacker can capture the token (e.g., via network sniffing or insecure client storage) and replay the request to place fraudulent orders or access protected resources. Even with HTTPS, if tokens are stored insecurely on the client or logged inadvertently, replay risk persists. Moreover, if the token’s payload includes sensitive data or elevated scopes, the impact is amplified because the same token may be accepted by multiple routes that trust the issuer.

Another angle involves timing and token binding. JWTs with long lifetimes increase the window for replay, and Fiber applications that do not enforce strict token invalidation (e.g., on logout) leave replay feasible. Because Fiber is fast and lightweight, developers might skip additional anti-replay checks, assuming HTTPS and signature validation suffice. However, replay is a transport-layer concern that exists independently of cryptographic integrity; without mechanisms such as one-time nonces, per-request signatures, or server-side denylists, JWTs in Fiber remain susceptible to replay. The scanner’s checks for Authentication and Data Exposure help surface these gaps by identifying missing anti-replay controls and overly permissive token acceptance.

Jwt Tokens-Specific Remediation in Fiber — concrete code fixes

To mitigate replay attacks in Fiber with JWT tokens, implement per-request uniqueness and server-side tracking. Below are concrete code examples using the github.com/gofiber/fiber/v2 package along with a JWT middleware and a custom validation layer.

1. Include a JTI (JWT ID) claim and maintain a denylist

Assign a unique identifier (jti) to each token at issuance and store recently used JTIs in a short-lived cache (e.g., Redis) to reject replays. This approach limits reuse within the token’s validity period.

package main

import (
	"context"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/jwt"
)

var jtiStore = map[string]bool{} // in production, use Redis with TTL

func main() {
	app := fiber.New()

	app.Post("/login", func(c *fiber.Ctx) error {
		// After validating credentials, issue a JWT with a unique jti
		token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmJmIjoxNzE2MjM5MDIyLCJleHAiOjE3MTYyNDI2MjIsImp0aSI6IjFlOWYwYjBjLTRmODQtNDNjNy1hYjM0LWI2YzQxYzJmZjdiZSIsInRpY2siOiJ0ZXN0LWp0aS10aW1lIn0.signature"
		// In practice, sign with private key and include jti in payload
		return c.SendString(token)
	})

	app.Post("/order", jwtMiddleware(), func(c *fiber.Ctx) error {
		claims := c.Locals("user").(*jwt.Token).Claims()
		jti := claims["jti"].(string)

		if isReplayed(jti) {
			return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "token_replayed"})
		}
		markReplayed(jti)
		// Proceed with order logic
		return c.JSON(fiber.Map{"status": "order_created"})
	})

	app.Listen(":3000")
}

func isReplayed(jti string) bool {
	_, exists := jtiStore[jti]
	return exists
}

func markReplayed(jti string) {
	jtiStore[jti] = true
}

func jwtMiddleware() fiber.Handler {
	return jwt.New(jwt.Config{
		SigningKey:   []byte("secret"),
		ContextKey:   "user",
		Expiration:   3600,
		SigningMethod: "HS256",
	})
}

2. Use short-lived tokens and refresh token rotation

Issue short-lived access tokens (e.g., 5–15 minutes) and use refresh tokens with rotation. Store refresh token identifiers and invalidate used ones to prevent replay of access tokens via stolen refresh flows.

package main

import (
	"time"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/jwt"
)

var refreshStore = map[string]time.Time{} // refresh token ID -> expiry

func issueTokens(c *fiber.Ctx) error {
	accessJTI := "unique-access-id-123"
	refreshJTI := "unique-refresh-id-456"
	// Store refreshJTI with expiry
	refreshStore[refreshJTI] = time.Now().Add(7 * 24 * time.Hour)

	accessToken := generateJWT(map[string]interface{}{"jti": accessJTI, "exp": time.Now().Add(10 * time.Minute).Unix()})
	refreshToken := generateJWT(map[string]interface{}{"jti": refreshJTI, "exp": time.Now().Add(7 * 24 * time.Hour).Unix()})
	return c.JSON(fiber.Map{
		"access_token":  accessToken,
		"refresh_token": refreshToken,
	})
}

func refreshTokenHandler(c *fiber.Ctx) error {
	var req struct {
		RefreshToken string `json:"refresh_token"`
	}
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid_request"})
	}
	// Validate refresh token signature and check jti against refreshStore
	jti := extractJTI(req.RefreshToken)
	if expiry, ok := refreshStore[jti]; !ok || time.Now().After(expiry) {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "invalid_token"})
	}
	// Rotate: issue new refresh token and revoke old
	delete(refreshStore, jti)
	return issueTokens(c)
}

func generateJWT(claims map[string]interface{}) string {
	// Use a proper JWT library to sign; this is illustrative
	return "signed.jwt.token"
}

func extractJTI(token string) string {
	// Parse token header/payload; this is illustrative
	return "extracted-jti"
}

3. Add nonce or timestamp binding for critical endpoints

For high-risk actions, bind the request to a nonce or timestamp included in the JWT and verified server-side to ensure freshness.

package main

import (
	"errors"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/jwt"
)

var usedNonces = map[string]bool{}

func criticalAction(c *fiber.Ctx) error {
	claims := c.Locals("user").(*jwt.Token).Claims()
	nonce := claims["nonce"].(string)
	if usedNonces[nonce] {
		return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "nonce_reused"})
	}
	// Optionally check exp within payload for freshness
	usedNonces[nonce] = true
	// Perform action
	return c.JSON(fiber.Map{"result": "success"})
}

These concrete fixes—JTI denylisting, short-lived tokens with refresh rotation, and nonce binding—reduce the feasibility of replay attacks against Fiber APIs using JWT tokens. The scanner’s Authentication and Data Exposure checks can highlight missing jti usage, long-lived tokens, and lack of replay detection to guide remediation.

Frequently Asked Questions

Does middleBrick fix replay vulnerabilities automatically?
No. middleBrick detects and reports replay-related findings, such as missing JTI usage or long-lived tokens, and provides remediation guidance. It does not automatically patch or block attacks.
Can replay detection be added via OpenAPI spec analysis?
Yes. If your OpenAPI/Swagger spec documents security schemes, anti-replay measures like JTI enforcement or nonce requirements, middleBrick’s spec analysis correlates these design intentions with runtime behavior to identify gaps.