Brute Force Attack in Hapi with Basic Auth
Brute Force Attack in Hapi with Basic Auth — how this specific combination creates or exposes the vulnerability
A brute force attack against an Hapi service using HTTP Basic Authentication relies on repeatedly submitting username and password combinations to discover valid credentials. Because Basic Auth encodes credentials in an easily reversible format (Base64) and typically lacks built-in rate control, an unauthenticated attacker can iterate through passwords at scale. In Hapi, if routes relying on basic auth do not enforce strict request limits or account lockout, each request is a discrete authentication attempt that can be automated with minimal detection risk.
The attack surface is shaped by how Hapi is configured. For example, if route authentication is implemented via a simple auth strategy without additional protections, an attacker can probe accounts using captured traffic or open endpoints. Without mechanisms such as incremental delays, token-based challenges, or secondary confirmation after repeated failures, the service remains vulnerable to online password guessing. Each failed attempt returns a 401 response, confirming that the username exists and the password was incorrect, which guides subsequent guesses.
During a black-box scan, tools can enumerate valid accounts by analyzing response codes and timing differences. If Hapi responses do not standardize error messages or use consistent response times, attackers can distinguish successful authentication from failed attempts. This becomes especially critical when usernames are predictable, such as emails or common identifiers, which are often exposed through other means like data leaks or social engineering.
Because middleBrick tests unauthenticated attack surfaces, it can detect missing rate limiting, inconsistent error handling, and weak account policies that facilitate brute force attempts. The scan checks whether the API enforces throttling, uses secure challenge-response mechanisms, and applies account lockout or other adaptive protections. These checks align with the Authentication and Rate Limiting categories in middleBrick’s 12 security checks, providing visibility into whether brute force risks are mitigated in deployed services.
Real-world attack patterns such as credential stuffing amplify the risk when reused passwords meet weak account protections. Even without credentials, attackers can mount low-volume, long-duration brute force campaigns that evade simple threshold-based defenses. Therefore, defense in Hapi must combine transport security, account policies, and observable protections that prevent rapid, automated guessing.
Basic Auth-Specific Remediation in Hapi — concrete code fixes
Securing Hapi endpoints that use Basic Authentication requires deliberate server-side controls. The following examples show a hardened configuration that combines proper validation, secure password storage, and rate limiting to reduce brute force risk.
// Hapi server with secure Basic Auth setup
const Hapi = require('@hapi/hapi');
const bcrypt = require('bcrypt');
const RateLimiter = require('hapi-ratelimiter');
const users = new Map([
// In production, retrieve this from a secure store
// Store only hashed passwords
['alice', await bcrypt.hash('StrongPass!2025', 10)]
]);
const validate = async (request, username, password, h) => {
const hashed = users.get(username);
if (!hashed) {
// Avoid user enumeration by performing a dummy hash check
await bcrypt.hash('dummy', 10);
return { isValid: false };
}
const isValid = await bcrypt.compare(password, hashed);
return { isValid, credentials: { username, scope: ['user'] } };
};
const init = async () => {
const server = Hapi.server({ port: 4000, host: 'localhost' });
// Apply rate limiting to limit authentication attempts
const limiter = new RateLimiter({
rate: 5, // 5 requests
window: 60 // per 60 seconds per key
});
server.ext('onPreAuth', limiter.validator);
server.auth.strategy('simple', 'basic', {
validateFunc: validate,
allowAdminHeader: false
});
server.route({
method: 'GET',
path: '/secure',
options: {
auth: 'simple',
handler: (request, h) => {
return { message: `Authenticated as ${request.auth.credentials.username}` };
},
response: {
// Standardize error responses to avoid information leakage
failAction: (request, h, error) => {
return h.response({ error: 'Unauthorized' }).code(401).takeover();
}
}
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.error(err);
process.exit(1);
});
This example demonstrates several key practices:
- Password hashing with
bcryptusing a sufficient work factor to resist offline cracking if the user database is compromised. - A custom validate function that avoids user enumeration by running a dummy hash comparison when the username is not found, ensuring consistent timing characteristics.
- Rate limiting via
hapi-ratelimiterapplied at the pre-authentication phase to restrict the number of authentication attempts per time window. - Standardized failure responses that return a generic 401 payload, preventing attackers from distinguishing between invalid usernames and incorrect passwords.
Additional measures should include enforcing HTTPS to protect credentials in transit, using secure and HttpOnly cookies if sessions are issued, and integrating account lockout or exponential backoff after repeated failures. These controls complement Basic Auth and align with the Authentication, Rate Limiting, and Data Exposure checks performed by middleBrick to ensure the API’s resilience against brute force attempts.