Information Disclosure with Basic Auth
How Information Disclosure Manifests in Basic Auth
Information disclosure in Basic Authentication occurs when sensitive authentication data is exposed through improper implementation or configuration. The most common manifestation is when Basic Auth credentials are transmitted without proper encryption, allowing attackers to intercept and decode the Base64-encoded credentials.
When a client sends an Authorization header with Basic scheme, the format is:
Authorization: Basic <base64-encoded-credentials>The credentials follow the pattern username:password, which Base64 encodes to something like Basic dXNlcm5hbWU6cGFzc3dvcmQ=. While Base64 is not encryption, many developers mistakenly believe it provides security. An attacker who intercepts this header can simply decode it:
const encoded = 'dXNlcm5hbWU6cGFzc3dvcmQ=';
const decoded = Buffer.from(encoded, 'base64').toString('utf8');
// Result: 'username:password'
Information disclosure also occurs when Basic Auth is implemented over HTTP instead of HTTPS. Without TLS, credentials travel in plaintext across the network, visible to anyone with packet capture capabilities. This is particularly dangerous in public Wi-Fi environments or compromised network segments.
Another disclosure vector is improper error handling. When authentication fails, some implementations return detailed error messages revealing whether the username exists, password requirements, or system information. For example:
// INSECURE - reveals too much information
if (!user) {
res.status(401).json({ error: 'User not found' });
} else if (!validPassword) {
res.status(401).json({ error: 'Invalid password' });
}
This pattern allows attackers to enumerate valid usernames through systematic probing. Secure implementations should return generic error messages like 'Invalid credentials' regardless of the failure reason.
Basic Auth implementations may also inadvertently log sensitive credentials. Debug logging that captures request headers, database query logs that include authentication parameters, or application logs that store Authorization headers all constitute information disclosure vulnerabilities.
Basic Auth-Specific Detection
Detecting information disclosure in Basic Auth implementations requires examining both network traffic and application behavior. Network-level detection focuses on identifying Basic Auth headers transmitted over non-TLS connections or to endpoints that should require stronger authentication.
Manual detection involves capturing network traffic during authentication attempts. Using tools like Wireshark or tcpdump, you can filter for Authorization headers:
tcpdump -A -s 0 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x4745544f)'
This captures HTTP traffic where Basic Auth headers might appear. Look for Authorization headers with Basic scheme on port 80 or other non-secure channels.
Automated scanning with middleBrick specifically tests Basic Auth endpoints for information disclosure vulnerabilities. The scanner examines:
- Whether Basic Auth is offered over HTTP instead of HTTPS
- If credentials are transmitted in URLs (e.g.,
http://user:[email protected]) - Whether error responses reveal system information
- If Authorization headers appear in server logs or error messages
- Whether authentication attempts are throttled to prevent credential enumeration
middleBrick's black-box scanning approach tests the actual runtime behavior without requiring source code access. For Basic Auth endpoints, it attempts authentication over various channels and analyzes responses for disclosure patterns.
Code review detection involves searching for common Basic Auth implementation patterns that lead to disclosure:
// Search for these patterns in your codebase
grep -r 'Authorization.*Basic' --include='*.js' --include='*.ts'
grep -r 'www-authenticate' --include='*.js' --include='*.ts'
Look for instances where credentials might be logged, error messages reveal too much, or authentication occurs over insecure channels.
Basic Auth-Specific Remediation
Remediating information disclosure in Basic Auth implementations requires a multi-layered approach focusing on secure transmission, proper error handling, and secure coding practices.
The foundation of remediation is enforcing HTTPS for all authentication traffic. In Node.js/Express applications, this means configuring TLS termination and redirecting HTTP to HTTPS:
const express = require('express');
const helmet = require('helmet');
const app = express();
// Enforce HTTPS
app.use(helmet({
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
// Redirect HTTP to HTTPS
app.use((req, res, next) => {
if (req.secure) {
return next();
}
res.redirect(301, `https://${req.headers.host}${req.url}`);
});
For error handling, implement generic authentication failure responses:
app.post('/login', (req, res) => {
const { username, password } = req.body;
// Always use constant-time comparison to prevent timing attacks
if (!username || !password) {
return res.status(401).json({
error: 'Invalid credentials'
});
}
// Lookup user and validate password
const user = users.find(u => u.username === username);
if (!user || !comparePasswords(password, user.passwordHash)) {
// Generic error - don't reveal which check failed
return res.status(401).json({
error: 'Invalid credentials'
});
}
// Successful authentication
res.json({ token: generateJwt(user) });
});
Prevent credential logging by sanitizing request data before logging:
const expressWinston = require('express-winston');
app.use(expressWinston.logger({
transports: [new winston.transports.Console()],
format: winston.format.combine(
winston.format.colorize(),
winston.format.json()
),
// Skip sensitive headers
requestFilter: (req, propName) => {
if (propName === 'authorization') return undefined;
return req[propName];
},
// Mask sensitive data in body
bodyBlacklist: ['password', 'token', 'apiKey']
}));
Implement rate limiting to prevent credential enumeration attacks:
const rateLimit = require('express-rate-limit');
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
message: 'Too many authentication attempts'
});
// Apply rate limiting to authentication routes
app.use('/api/auth', authLimiter);
For applications using Basic Auth for API access, consider implementing API keys with proper scope limitations instead of user credentials:
// Generate secure API keys
function generateApiKey() {
return crypto.randomBytes(32).toString('hex');
}
// Store hashed API keys
const apiKeyHash = crypto.createHash('sha256')
.update(apiKey)
.digest('hex');
// Validate API key with constant-time comparison
function validateApiKey(headerKey, storedHash) {
const headerHash = crypto.createHash('sha256')
.update(headerKey)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(headerHash),
Buffer.from(storedHash)
);
}