HIGH brute force attackhapi

Brute Force Attack in Hapi

How Brute Force Attack Manifests in Hapi

Brute force attacks targeting Hapi applications typically exploit authentication endpoints where attackers systematically attempt to guess valid credentials. In Hapi, this commonly occurs at login routes that validate user credentials without proper rate limiting or account lockout mechanisms.

A typical Hapi authentication implementation might look like this:

const Hapi = require('@hapi/hapi');

const server = Hapi.server({ port: 3000 });

server.route({
  method: 'POST',
  path: '/login',
  handler: async (request, h) => {
    const { username, password } = request.payload;
    const user = await db.findUser(username);
    
    if (user && await bcrypt.compare(password, user.hash)) {
      return h.response({ token: generateToken(user) }).code(200);
    }
    
    return h.response('Invalid credentials').code(401);
  }
});

The vulnerability in this code is the lack of any mechanism to track failed authentication attempts. An attacker can send unlimited requests to this endpoint, trying different username/password combinations until they find valid credentials. Without rate limiting, the server processes each request normally, consuming resources and potentially allowing thousands of attempts per minute.

Hapi's plugin architecture makes it particularly susceptible to brute force attacks when developers create custom authentication schemes. A naive implementation might look like:

const { validate } = require('./auth-strategy');

server.auth.strategy('simple', 'custom', {
  validate: async (request, username, password) => {
    const user = await db.findUser(username);
    if (!user || !(await bcrypt.compare(password, user.hash))) {
      return { isValid: false };
    }
    return { isValid: true, credentials: user };
  }
});

server.route({
  method: 'POST',
  path: '/protected',
  options: {
    auth: 'simple'
  },
  handler: (request, h) => {
    return { message: 'Access granted' };
  }
});

This pattern is dangerous because the validate function executes on every request, and without rate limiting, an attacker can flood the endpoint with authentication attempts. The server's CPU cycles are consumed by repeated bcrypt comparisons, potentially leading to a denial of service condition.

Another Hapi-specific scenario involves JWT token validation in route handlers:

server.route({
  method: 'POST',
  path: '/api/data',
  handler: async (request, h) => {
    const token = request.headers.authorization?.replace('Bearer ', '');
    if (!token) return h.response('Missing token').code(401);
    
    try {
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      return await db.getData(decoded.userId);
    } catch (err) {
      return h.response('Invalid token').code(401);
    }
  }
});

Here, attackers can generate random JWT tokens and send them in rapid succession. Without rate limiting, the server attempts to verify each token, consuming CPU resources with cryptographic operations. The error handling is uniform (always returning 401), providing no feedback about which part of the token validation failed, but the computational cost remains significant.

Hapi-Specific Detection

Detecting brute force vulnerabilities in Hapi applications requires examining both the authentication logic and the rate limiting implementation. The most effective approach combines static code analysis with runtime scanning.

Static analysis should focus on identifying authentication endpoints and examining their security controls. Look for patterns like:

server.route({
  method: 'POST',
  path: '/login',
  handler: (request, h) => {
    // Authentication logic without rate limiting
  }
});

Search for authentication handlers that lack any form of request throttling, IP-based restrictions, or account lockout mechanisms. Pay special attention to custom authentication strategies where developers implement their own validate functions without security controls.

Runtime detection with middleBrick provides comprehensive coverage by actively testing your Hapi endpoints. The scanner identifies authentication routes and attempts controlled brute force attacks to verify if protections exist. It tests for:

  • Rate limiting effectiveness by sending rapid sequential requests
  • Account lockout mechanisms by attempting multiple failed logins
  • IP-based restrictions by varying request origins
  • Response consistency that might indicate lack of throttling

middleBrick's API security scanner specifically tests Hapi applications by sending authenticated and unauthenticated requests to identify vulnerable endpoints. The scanner's LLM/AI security module can also detect if your Hapi application exposes AI/ML endpoints that might be susceptible to prompt injection or excessive agency attacks.

Network-level detection involves monitoring for unusual traffic patterns. Hapi applications under brute force attack typically show:

IndicatorDescription
Sudden traffic spikesUnusual increase in requests to authentication endpoints
Geographic anomaliesRequests from unexpected geographic locations
Consistent failure ratesHigh percentage of authentication failures
Resource exhaustionIncreased CPU/memory usage during authentication attempts

Implementing logging in your Hapi application helps with detection:

const { logger } = require('./logging');

server.ext('onRequest', (request, h) => {
  logger.info(`Request: ${request.method} ${request.path} from ${request.info.remoteAddress}`);
  return h.continue;
});

// Add rate limiting metrics
const rateLimitPlugin = {
  name: 'rate-limit',
  register: async (server, options) => {
    server.ext('onRequest', async (request, h) => {
      const key = request.info.remoteAddress;
      const current = await getRateLimit(key);
      
      if (current > options.maxRequests) {
        logger.warn(`Rate limit exceeded for ${key}`);
        return h.response('Too many requests').code(429);
      }
      
      return h.continue;
    });
  }
};

middleBrick's continuous monitoring feature (Pro plan) can automatically scan your Hapi APIs on a configurable schedule, alerting you when new vulnerabilities are detected or when security scores drop below your defined thresholds.

Hapi-Specific Remediation

Remediating brute force vulnerabilities in Hapi applications requires implementing multiple layers of protection. The most effective approach combines rate limiting, account lockout mechanisms, and monitoring.

Rate limiting is the first line of defense. Hapi provides excellent support through plugins like hapi-rate-limitor:

const RateLimit = require('hapi-rate-limitor');

const server = Hapi.server({ port: 3000 });

server.register({
  plugin: RateLimit,
  options: {
    userLimit: 5,           // 5 requests per user
    userCache: 60000,       // 60 seconds
    ipLimit: 10,            // 10 requests per IP
    ipCache: 60000,
    endpointLimits: {
      '/login': { limit: 3, cache: 300000 }, // 3 attempts per 5 minutes
      '/api/*': { limit: 100, cache: 60000 }
    }
  }
});

For authentication endpoints specifically, implement exponential backoff:

const loginAttempts = new Map();

server.route({
  method: 'POST',
  path: '/login',
  handler: async (request, h) => {
    const ip = request.info.remoteAddress;
    const now = Date.now();
    
    // Initialize or update attempt tracking
    if (!loginAttempts.has(ip)) {
      loginAttempts.set(ip, { count: 0, firstAttempt: now });
    }
    
    const attempts = loginAttempts.get(ip);
    const timeSinceFirst = now - attempts.firstAttempt;
    const elapsedMinutes = timeSinceFirst / 60000;
    
    // Calculate allowed attempts with exponential backoff
    const maxAttempts = Math.floor(5 * Math.log(elapsedMinutes + 1) + 3);
    
    if (attempts.count >= maxAttempts) {
      const waitTime = Math.pow(2, attempts.count - maxAttempts) * 1000;
      return h.response('Too many attempts').code(429).header('Retry-After', waitTime / 1000);
    }
    
    // Process authentication
    const { username, password } = request.payload;
    const user = await db.findUser(username);
    
    if (user && await bcrypt.compare(password, user.hash)) {
      loginAttempts.delete(ip); // Clear on success
      return h.response({ token: generateToken(user) }).code(200);
    }
    
    // Increment failed attempts
    attempts.count += 1;
    loginAttempts.set(ip, attempts);
    
    return h.response('Invalid credentials').code(401);
  }
});

Account lockout provides another security layer:

const accountLockouts = new Map();

const MAX_FAILED_ATTEMPTS = 5;
const LOCKOUT_DURATION = 15 * 60 * 1000; // 15 minutes

async function withLockout(username, handler) {
  const lockoutKey = `lockout:${username}`;
  const lockout = await cache.get(lockoutKey);
  
  if (lockout) {
    const remaining = Math.max(0, lockout.expires - Date.now());
    if (remaining > 0) {
      return { error: 'Account locked', retryAfter: remaining / 1000 };
    }
    await cache.delete(lockoutKey);
  }
  
  const result = await handler();
  
  if (result.error === 'invalid-credentials') {
    const attemptsKey = `attempts:${username}`;
    let attempts = await cache.get(attemptsKey) || 0;
    attempts += 1;
    
    if (attempts >= MAX_FAILED_ATTEMPTS) {
      await cache.set(lockoutKey, { expires: Date.now() + LOCKOUT_DURATION });
      await cache.delete(attemptsKey);
      return { error: 'Account locked', retryAfter: LOCKOUT_DURATION / 1000 };
    }
    
    await cache.set(attemptsKey, attempts, { ttl: 300 }); // 5 minute window
  } else if (result.success) {
    // Clear attempts on successful login
    const attemptsKey = `attempts:${username}`;
    await cache.delete(attemptsKey);
  }
  
  return result;
}

Integrate with Hapi's authentication system:

const validate = async (request, username, password) => {
  const result = await withLockout(username, async () => {
    const user = await db.findUser(username);
    if (!user || !(await bcrypt.compare(password, user.hash))) {
      return { error: 'invalid-credentials' };
    }
    return { success: true, credentials: user };
  });
  
  if (result.error) {
    if (result.error === 'Account locked') {
      throw new Error(`Account locked. Try again in ${Math.ceil(result.retryAfter)} seconds.`);
    }
    return { isValid: false };
  }
  
  return { isValid: true, credentials: result.credentials };
};

For production deployments, combine these techniques with monitoring and alerting. middleBrick's Pro plan includes continuous monitoring that can alert you when brute force patterns are detected, helping you identify and respond to attacks before they succeed.

Frequently Asked Questions

How can I test if my Hapi application is vulnerable to brute force attacks?
Use middleBrick's API security scanner to test your Hapi endpoints. The scanner actively attempts brute force attacks on authentication routes to verify if rate limiting and account lockout mechanisms are properly implemented. It provides a security score (A-F) with specific findings about brute force vulnerabilities and actionable remediation guidance.
Does middleBrick's CLI tool work with Hapi applications?
Yes, the middleBrick CLI tool works with any API endpoint, including Hapi applications. Install it with npm install -g middlebrick, then run middlebrick scan https://yourapi.com to scan your Hapi API. The CLI provides the same comprehensive security analysis as the web dashboard, including brute force vulnerability detection.