Log Injection with Basic Auth
How Log Injection Manifests in Basic Auth
Log injection in Basic Auth systems occurs when an attacker crafts credentials that exploit how authentication logs are processed. The most common attack vector involves the username field, where special characters can break out of intended log contexts.
Consider a typical Basic Auth implementation:
const http = require('http');
const auth = require('basic-auth');
const server = http.createServer((req, res) => {
const credentials = auth(req);
if (!credentials) {
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="example"');
res.end('Unauthorized');
return;
}
const { name: username, pass: password } = credentials;
// Vulnerable logging
console.log(`Auth attempt: user=${username}, password=${password}`);
if (username === 'admin' && password === 'secret') {
res.end('Welcome admin');
} else {
res.end('Invalid credentials');
}
});The vulnerability appears in the logging statement. An attacker can submit a username like:
adminBasic Auth-Specific Detection
Detecting log injection in Basic Auth systems requires examining both the authentication code and the logging infrastructure. Here's how to identify this vulnerability:
Code Review Checklist:
- Look for direct string interpolation in log statements that include username or password values
- Check if log messages use structured formats (JSON, key-value pairs) that could be manipulated
- Verify if log sanitization occurs before authentication logging
- Examine if logs are written to files or systems that parse structured data
Automated Scanning with middleBrick:
middleBrick's black-box scanning approach can detect log injection vulnerabilities in Basic Auth endpoints without requiring source code access. The scanner tests for:
- Special character handling in username fields
- Structured data injection attempts
- Newline and control character processing
- Log format manipulation
The scanner attempts payloads like:
username=testBasic Auth-Specific Remediation
Fixing log injection in Basic Auth systems involves proper input sanitization and secure logging practices. Here are specific remediation strategies:
1. Sanitize Log Inputs:
const http = require('http');
const auth = require('basic-auth');
function sanitizeLogInput(input) {
return input
.replace(/
/g, '\n')
.replace(/
/g, '\r')
.replace(/ /g, '\t')
.replace(/,/g, ', ')
.replace(/:/g, ': ');
}
const server = http.createServer((req, res) => {
const credentials = auth(req);
if (!credentials) {
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="example"');
res.end('Unauthorized');
return;
}
const { name: username, pass: password } = credentials;
// Secure logging with sanitization
console.log(`Auth attempt: user=${sanitizeLogInput(username)},
password=[FILTERED], success=false`);
if (username === 'admin' && password === 'secret') {
console.log(`Auth successful: user=${sanitizeLogInput(username)}`);
res.end('Welcome admin');
} else {
res.end('Invalid credentials');
}
});2. Use Structured Logging with Validation:
const winston = require('winston');
const logger = winston.createLogger({
format: winston.format.json(),
transports: [new winston.transports.Console()]
});
function validateAuthLogData(data) {
const allowedKeys = ['username', 'ip', 'timestamp', 'success'];
return Object.keys(data).every(key => allowedKeys.includes(key));
}
const server = http.createServer((req, res) => {
const credentials = auth(req);
if (!credentials) {
res.statusCode = 401;
res.end('Unauthorized');
return;
}
const { name: username } = credentials;
const authLogData = {
username: sanitizeLogInput(username),
ip: req.connection.remoteAddress,
timestamp: new Date().toISOString(),
success: false
};
if (validateAuthLogData(authLogData)) {
logger.info('Authentication attempt', authLogData);
}
if (username === 'admin') {
logger.info('Authentication successful', { ...authLogData, success: true });
res.end('Welcome admin');
} else {
res.end('Invalid credentials');
}
});3. Implement Rate Limiting and Monitoring:
const rateLimit = require('express-rate-limit');
const authAttemptLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 requests
message: 'Too many authentication attempts',
keyGenerator: req => req.connection.remoteAddress
});
// Apply rate limiting to Basic Auth endpoints
app.use('/api/auth', authAttemptLimiter);4. Use Framework-Specific Security Features:
With Express and Passport:
const express = require('express');
const passport = require('passport');
const BasicStrategy = require('passport-http').BasicStrategy;
passport.use(new BasicStrategy((username, password, done) => {
// Validate credentials
if (username === 'admin' && password === 'secret') {
return done(null, { id: 1 });
}
return done(null, false);
}));
app.use((req, res, next) => {
// Log authentication attempts securely
const logData = {
username: sanitizeLogInput(req.body?.username || ''),
ip: req.ip,
timestamp: new Date().toISOString()
};
logger.info('Auth attempt', logData);
next();
});These remediation strategies ensure that Basic Auth implementations remain secure against log injection attacks while maintaining proper audit trails for legitimate security monitoring.