Side Channel Attack in Fiber with Basic Auth
Side Channel Attack in Fiber with Basic Auth — how this specific combination creates or exposes the vulnerability
A side channel attack in the Fiber web framework using HTTP Basic Auth does not break the cryptographic algorithm of Base64 encoding, but it leverages observable runtime behavior to infer valid credentials. Basic Auth encodes a username:password pair into Base64 and sends it in the Authorization header on every request. Because Base64 is easily reversible, the protection relies entirely on transport layer security (TLS). In practice, side channels arise not from the encoding itself, but from how the server handles malformed or missing credentials.
In Fiber, a typical pattern uses middleware to extract and validate credentials. Consider a naive implementation that compares the provided password against a stored hash:
const Fiber = require('fiber');
const app = new Fiber();
const USERS = {
admin: '$2b$10$abc123...' // bcrypt hash
};
app.use((req, res, next) => {
const authHeader = req.headers['authorization'];
if (!authHeader || !authHeader.startsWith('Basic ')) {
res.status(401).send('Unauthorized');
return;
}
const base64 = authHeader.split(' ')[1];
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
const [user, pass] = decoded.split(':');
const userRecord = USERS[user];
if (userRecord && userRecord === pass) { // Timing-sensitive comparison
req.user = user;
next();
} else {
res.status(401).send('Unauthorized');
}
});
This example illustrates multiple side channel risks. First, the timing of the comparison is variable; an attacker can measure response times to perform a timing attack and iteratively guess the password character by character. Second, if the application does not enforce strict input validation on the username, it may leak information through error messages or stack traces, aiding username enumeration. Third, the absence of rate limiting enables credential stuffing or brute force attempts at network speed, making online attacks feasible. Because the scan category Authentication in middleBrick specifically tests for these weaknesses, such implementations would be flagged with high severity findings related to insecure credential handling and missing protections.
Furthermore, TLS misconfiguration compounds the issue. Basic Auth over non-TLS connections exposes credentials in clear text, while weak cipher suites or expired certificates degrade the trust boundary. The scan category Encryption would detect missing or improper TLS usage, while Input Validation would highlight missing sanitization of the username and password fields. Together, these create a multi-vector side channel where timing differences, error responses, and network-level exposures interact to undermine the intended security of Basic Auth.
middleBrick identifies these risks by correlating its 12 parallel checks. For example, SSRF and Unsafe Consumption checks ensure that the endpoint does not inadvertently forward credentials or leak internal network details. The LLM/AI Security category examines whether error messages or documentation might prompt AI-driven clients to misuse authentication flows. Because middleBrick performs black-box testing against the unauthenticated attack surface, it can detect timing irregularities and missing rate limiting without access to source code.
Basic Auth-Specific Remediation in Fiber — concrete code fixes
Remediation focuses on eliminating timing variability, enforcing transport security, and adding operational protections. The primary rule is to avoid manual credential comparison. Instead, use a constant-time comparison and delegate authentication to a well-audited library. Below is a secure Fiber implementation using bcrypt for password hashing and proper middleware structure.
const Fiber = require('fiber');
const bcrypt = require('bcrypt');
const app = new Fiber();
const USERS = {
admin: await bcrypt.hash('SuperSecret123!', 10)
};
// Constant-time comparison helper
const safeCompare = (a, b) => {
if (a.length !== b.length) return false;
let result = 0;
for (let i = 0; i < a.length; i++) {
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return result === 0;
};
app.use(async (req, res, next) => {
const authHeader = req.headers['authorization'];
if (!authHeader || !authHeader.startsWith('Basic ')) {
res.status(401).set('WWW-Authenticate', 'Basic').send('Unauthorized');
return;
}
try {
const base64 = authHeader.split(' ')[1];
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
const [user, pass] = decoded.split(':');
if (!user || !pass) {
res.status(401).set('WWW-Authenticate', 'Basic').send('Unauthorized');
return;
}
const userRecord = USERS[user];
if (!userRecord) {
// Still run a dummy hash to keep timing consistent
await bcrypt.hash('dummy', 10);
res.status(401).set('WWW-Authenticate', 'Basic').send('Unauthorized');
return;
}
const match = await bcrypt.compare(pass, userRecord);
if (!safeCompare(user, 'admin') || !match) {
res.status(401).set('WWW-Authenticate', 'Basic').send('Unauthorized');
return;
}
req.user = user;
next();
} catch (err) {
res.status(401).set('WWW-Authenticate', 'Basic').send('Unauthorized');
}
});
app.get('/secure', (req, res) => {
res.send(`Hello, ${req.user}`);
});
app.listen(3000);
Key remediation points include:
- Use bcrypt.compare for password verification to avoid timing leaks.
- Implement a constant-time string comparison for usernames to prevent timing attacks.
- Always return the same WWW-Authenticate header on failure to avoid username enumeration.
- Ensure TLS is enforced in production, as Basic Auth credentials are only safe over encrypted channels.
Complementary protections should be applied at the infrastructure or gateway level, such as rate limiting and IP allowlisting. middleBrick supports this remediation workflow by allowing you to rescan with the Pro plan to verify that timing and authentication checks now pass. The GitHub Action can enforce a minimum score before merging, while the MCP Server enables on-the-fly scanning from your AI coding assistant to validate changes in real time.