Password Spraying in Fiber with Basic Auth
Password Spraying in Fiber with Basic Auth — how this specific combination creates or exposes the vulnerability
Password spraying is an authentication attack technique where an adversary uses a small list of commonly used passwords against many accounts, rather than credential stuffing (one password per account). When an API built with Fiber relies on HTTP Basic Authentication and does not implement adequate rate limiting or account lockout, this combination becomes especially risky.
In a typical Fiber app, developers sometimes enable Basic Auth via middleware such as fiber.BasicAuth or a custom handler that reads the Authorization: Basic header, decodes the base64 payload, and compares the username and password in code. If the endpoint is publicly reachable and unauthenticated probing is allowed, an attacker can enumerate valid usernames (e.g., via timing differences, HTTP status codes, or API behavior) and then run a password spray using common passwords like Password1, Welcome1, or organization-specific terms.
Because Basic Auth transmits credentials in each request (even if base64-encoded, not encrypted) without additional protections, an attacker who successfully guesses a password gains immediate access to the associated identity. In APIs that expose sensitive data or administrative functions, this can lead to unauthorized data access or privilege escalation. The risk is compounded when the same credentials are reused across systems or when password policies are weak.
Consider an endpoint that enumerates users via timing or error messages before validating credentials. An attacker can first identify valid usernames, then perform a low-and-slow password spray to evade simple rate-based defenses. middleBrick’s Authentication and Rate Limiting checks are designed to detect weak defenses around Basic Auth by probing for account enumeration and insufficient throttling, highlighting findings mapped to OWASP API Top 10 and PCI-DSS controls.
Without continuous monitoring, such misconfigurations can persist across deployments. In a proactive scan, middleBrick can identify whether Basic Auth endpoints are vulnerable to enumeration and spray by analyzing runtime behavior and spec definitions, providing prioritized findings and remediation guidance rather than attempting automatic changes.
Basic Auth-Specific Remediation in Fiber — concrete code fixes
To reduce the risk of password spraying when using HTTP Basic Auth in Fiber, apply defense-in-depth measures: avoid sending passwords in the clear, enforce rate limits per user or IP, use constant-time comparisons, and avoid user enumeration.
Below are concrete, working examples for securing Basic Auth in a Fiber application.
1. Use HTTPS and avoid plaintext passwords
Always serve your API over TLS. Never store or compare passwords in plaintext. Store a salted, hashed representation (e.g., bcrypt) and compare hashes securely.
import "github.com/gofiber/fiber/v2"
import "golang.org/x/crypto/bcrypt"
func verifyPassword(hashedPassword, password string) bool {
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) == nil
}
// Example user store (replace with a real database)
var users = map[string]string{
"alice": "$2a$10$abc123...", // bcrypt hash of the user's password
}
func basicAuthMiddleware(c *fiber.Ctx) error {
user, pass, ok := c.BasicAuth(); ok && user != "" && pass != ""
if !ok {
return c.SendStatus(fiber.StatusUnauthorized)
}
hashed, exists := users[user]
if !exists || !verifyPassword(hashed, pass) {
// Use a generic, consistent response to avoid user enumeration
return c.SendStatus(fiber.StatusUnauthorized)
}
// Attach user to context for downstream handlers
c.Locals("user", user)
return c.Next()
}
app := fiber.New()
app.Use(basicAuthMiddleware)
2. Implement rate limiting and backoff
Apply rate limiting to authentication endpoints to slow down password spraying attempts. Use middleware that limits requests per IP or per user and returns consistent responses to avoid signaling which username is valid.
import "github.com/gofiber/fiber/v2"
import "github.com/gofiber/contrib/ratelimit"
import "golang.org/x/time/rate"
// Global rate limiter: 5 requests per second burst of 10
limiter := ratelimit.New(rate.NewLimiter(rate.Every(200*time.Millisecond), 10))
func authLimiter(c *fiber.Ctx) error {
// Apply to all auth-related routes or globally
if c.Path() == "/login" || c.Path() == "/api/auth" {
if allowed := limiter.Allow(); !allowed {
return c.SendStatus(fiber.StatusTooManyRequests)
}
}
return c.Next()
}
3. Avoid user enumeration
Ensure that authentication responses are uniform. Do not return different status codes or messages for "user not found" versus "invalid password." Always use the same HTTP status code and avoid detailed error information in production.
func loginHandler(c *fiber.Ctx) error {
user, pass, ok := c.BasicAuth()
if !ok {
// Always respond the same to prevent timing/behavioral leaks
return c.SendStatus(fiber.StatusUnauthorized)
}
hashed, exists := users[user]
if !exists {
// Still verify a dummy hash to keep timing similar
bcrypt.CompareHashAndPassword([]byte("$2a$10$dummy........................"), []byte(pass))
return c.SendStatus(fiber.StatusUnauthorized)
}
if bcrypt.CompareHashAndPassword([]byte(hashed), []byte(pass)) != nil {
return c.SendStatus(fiber.StatusUnauthorized)
}
c.Locals("user", user)
return c.Next()
}
For broader protection across your API surface, the Pro plan provides continuous monitoring and configurable scans that can flag weak authentication patterns and missing rate limits. The GitHub Action can enforce a minimum security score in CI/CD, failing builds if risky authentication configurations are detected before deployment.