Session Fixation with Basic Auth
How Session Fixation Manifests in Basic Auth
Session fixation in Basic Auth environments occurs through a distinct attack vector compared to cookie-based sessions. Since Basic Auth credentials are transmitted with every request in the Authorization header, attackers can exploit the stateless nature of this authentication scheme to maintain persistent access even after credentials should have been invalidated.
The most common Basic Auth fixation pattern involves an attacker pre-generating a valid Basic Auth header and forcing a victim to use it. Consider this attack flow:
const maliciousAuthHeader = 'Basic ' + Buffer.from('attacker:fixedpassword').toString('base64');
// Attacker sends this header in a crafted link or iframe
fetch('https://api.example.com/sensitive', {
headers: {
'Authorization': maliciousAuthHeader
}
});
When the victim accesses this resource, their browser may cache the credentials. Even if they later change their password, the attacker's pre-generated header remains valid until the server implements proper credential invalidation mechanisms.
Another fixation scenario occurs in Basic Auth implementations that use client certificates or API keys as passwords. An attacker who compromises a single API key can create a Basic Auth string that remains valid indefinitely:
// Compromised API key fixation
const fixedAuth = 'Basic ' + Buffer.from('api-client:' + compromisedApiKey).toString('base64');
// This header works until the API key is explicitly revoked
Basic Auth's lack of built-in session expiration makes it particularly vulnerable to fixation. Unlike cookie-based sessions with timeout mechanisms, Basic Auth credentials remain valid until explicitly rejected by the server. This creates scenarios where:
- Stolen Basic Auth headers remain valid indefinitely
- Password changes don't automatically invalidate existing sessions
- Credential rotation becomes a manual, error-prone process
The fixation risk compounds when Basic Auth is used with stateless microservices. Each service independently validates the Authorization header without centralized session management, making coordinated invalidation nearly impossible.
Basic Auth-Specific Detection
Detecting Basic Auth session fixation requires examining both the authentication implementation and runtime behavior. The key indicators include:
Credential Persistence Analysis
Examine whether your Basic Auth implementation allows credential reuse across different contexts. Test with tools like middleBrick's API security scanner, which specifically checks for Basic Auth vulnerabilities including fixation risks:
# Scan for Basic Auth fixation vulnerabilities
middlebrick scan https://api.example.com --auth-type basic
The scanner tests for patterns like:
- Pre-generated Authorization headers that bypass normal authentication flows
- Credential caching mechanisms that persist Basic Auth strings
- Lack of credential rotation or expiration policies
Runtime Header Analysis
Monitor for suspicious Authorization header patterns in your API traffic:
// Log and analyze Basic Auth headers for fixation attempts
app.use((req, res, next) => {
const authHeader = req.headers.authorization;
if (authHeader && authHeader.startsWith('Basic ')) {
const decoded = Buffer.from(authHeader.split(' ')[1], 'base64').toString();
const [user, pass] = decoded.split(':');
// Check for known compromised credentials
if (isKnownCompromisedCredential(user, pass)) {
return res.status(401).json({ error: 'Authentication failed' });
}
}
next();
});
Credential Lifecycle Testing
Systematically test your Basic Auth implementation's response to credential changes:
// Test if password change invalidates existing sessions
async function testFixationResistance() {
// Initial authentication
const initialAuth = await authenticate('user', 'initialPass');
// Change password
await changePassword('user', 'initialPass', 'newPass');
// Verify old credentials no longer work
const oldAuthResult = await verifyAuth('user', 'initialPass');
const newAuthResult = await verifyAuth('user', 'newPass');
return {
oldCredentialsValid: oldAuthResult.success, // Should be false
newCredentialsValid: newAuthResult.success // Should be true
};
}
middleBrick's scanner automates these tests, checking whether credential changes propagate across all API endpoints and whether Basic Auth headers from previous sessions remain valid after authentication policy updates.
Basic Auth-Specific Remediation
Remediating Basic Auth fixation requires architectural changes beyond simple password policies. Here are effective Basic Auth-specific fixes:
Implement Credential Rotation with Server-Side Tracking
Rather than relying on static Basic Auth headers, implement a token-based system that tracks credential validity:
const crypto = require('crypto');
class BasicAuthManager {
constructor() {
this.validCredentials = new Map(); // username -> { token, timestamp }
}
generateAuthToken(username, password) {
const token = crypto.randomBytes(32).toString('hex');
this.validCredentials.set(username, {
token,
timestamp: Date.now(),
passwordHash: this.hashPassword(password)
});
return token;
}
createAuthHeader(username, token) {
const authString = `${username}:${token}`;
return 'Basic ' + Buffer.from(authString).toString('base64');
}
verifyAuth(header) {
if (!header.startsWith('Basic ')) return false;
const decoded = Buffer.from(header.split(' ')[1], 'base64').toString();
const [username, token] = decoded.split(':');
const cred = this.validCredentials.get(username);
if (!cred || cred.token !== token) return false;
// Implement fixation prevention: expire tokens after 1 hour
if (Date.now() - cred.timestamp > 3600000) {
this.validCredentials.delete(username);
return false;
}
return true;
}
invalidateUser(username) {
this.validCredentials.delete(username);
}
}
Server-Side Session Management for Basic Auth
Add server-side session tracking to Basic Auth to prevent fixation:
const sessions = new Map(); // sessionId -> { userId, createdAt, validUntil }
function createBasicAuthSession(userId) {
const sessionId = crypto.randomBytes(16).toString('hex');
const session = {
userId,
createdAt: Date.now(),
validUntil: Date.now() + 15 * 60 * 1000 // 15 minute timeout
};
sessions.set(sessionId, session);
return sessionId;
}
function validateBasicAuthSession(authHeader) {
if (!authHeader.startsWith('Basic ')) return false;
const decoded = Buffer.from(authHeader.split(' ')[1], 'base64').toString();
const [username, sessionId] = decoded.split(':');
const session = sessions.get(sessionId);
if (!session || session.userId !== username) return false;
// Check if session expired
if (Date.now() > session.validUntil) {
sessions.delete(sessionId);
return false;
}
// Prevent fixation by rotating session on each use
session.validUntil = Date.now() + 15 * 60 * 1000;
return true;
}
// Middleware to protect against fixation
app.use((req, res, next) => {
const authHeader = req.headers.authorization;
if (!validateBasicAuthSession(authHeader)) {
return res.status(401).json({ error: 'Invalid or expired session' });
}
next();
});
Credential Invalidation on Password Change
Ensure password changes immediately invalidate all existing Basic Auth sessions:
const userSessions = new Map(); // userId -> Set of active sessionIds
async function changePassword(userId, oldPassword, newPassword) {
// Verify old password
const user = await getUser(userId);
if (!await verifyPassword(oldPassword, user.passwordHash)) {
throw new Error('Invalid current password');
}
// Invalidate all existing sessions
const sessions = userSessions.get(userId) || new Set();
sessions.forEach(sessionId => sessions.delete(sessionId));
// Update password
user.passwordHash = await hashPassword(newPassword);
await updateUser(user);
return true;
}
These remediation strategies transform Basic Auth from a static credential system into a dynamic authentication framework that resists fixation attacks while maintaining Basic Auth's simplicity for clients.
Frequently Asked Questions
How does Basic Auth fixation differ from cookie-based session fixation?
Basic Auth fixation exploits the stateless nature of Authorization headers, where credentials travel with every request. Unlike cookie-based sessions that can be invalidated server-side through session storage, Basic Auth credentials remain valid until explicitly rejected. This makes Basic Auth fixation attacks more persistent and harder to detect, as the same Authorization header works across multiple services and requests without centralized session management.
Can middleBrick detect Basic Auth fixation vulnerabilities?
Yes, middleBrick's API security scanner specifically tests for Basic Auth fixation patterns. The scanner attempts to use pre-generated Authorization headers, tests credential persistence after password changes, and checks for lack of session expiration mechanisms. It provides detailed findings with severity ratings and remediation guidance, helping you identify whether your Basic Auth implementation is vulnerable to fixation attacks before attackers can exploit them.