Cross Site Request Forgery with Api Keys
How Cross Site Request Forgery Manifests in API Keys
Cross Site Request Forgery (CSRF) in API keys exploits the trust that servers place in client-side requests. Unlike session-based CSRF where cookies are automatically sent, API key CSRF requires the attacker to trick the victim into including their API key in a malicious request. This typically occurs when API keys are stored in browser storage (localStorage, sessionStorage) or when they're embedded in client-side code.
The most common API key CSRF vector involves storing the key in localStorage and making fetch requests with the Authorization header. When a user visits a malicious website, JavaScript can trigger requests to the target API using the victim's stored API key:
// Malicious site code that exploits API key CSRF
fetch('https://api.target.com/user/profile', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('apiKey'),
'Content-Type': 'application/json'
},
body: JSON.stringify({
'role': 'admin',
'email': '[email protected]'
})
});Another variation occurs with API keys embedded in JavaScript files or configuration objects. If an attacker can execute code on a page where the API key is accessible, they can construct requests that modify user data, transfer funds, or escalate privileges:
// API key exposed in client-side config
const API_CONFIG = {
baseUrl: 'https://api.target.com',
apiKey: 'sk-1234567890abcdef'
};
// Attacker code that changes user email
fetch(`${API_CONFIG.baseUrl}/users/${userId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${API_CONFIG.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email: '[email protected]' })
});CSRF attacks against API keys are particularly dangerous when the API lacks proper state-changing request validation. Without requiring custom headers, request bodies that change predictably, or re-authentication for sensitive operations, attackers can perform actions like changing passwords, updating payment methods, or transferring ownership of resources.
API Keys-Specific Detection
Detecting API key CSRF vulnerabilities requires examining how keys are stored, transmitted, and validated. The first step is identifying where API keys exist in your application's attack surface. MiddleBrick's black-box scanning approach tests for CSRF vulnerabilities by attempting state-changing operations without proper anti-CSRF tokens or custom headers.
Key detection patterns include:
- Storage analysis: Keys in localStorage, sessionStorage, or cookies without HttpOnly flags
- Client-side exposure: Keys embedded in JavaScript bundles or accessible via window objects
- Request validation: APIs that accept state-changing requests with only Authorization headers
- Same-origin policy bypass: APIs that don't validate Origin or Referer headers
MiddleBrick scans specifically test for these vulnerabilities by:
# Example scan output showing CSRF vulnerability
{
"category": "Authentication",
"severity": "high",
"finding": "API key stored in localStorage allows CSRF attacks",
"remediation": "Move API key storage to HttpOnly cookies or use double-submit cookie pattern",
"evidence": "Successful state-changing request without anti-CSRF token"
}Manual testing should include attempting to change user settings, update profile information, or perform financial transactions from a different origin. Tools like Burp Suite or OWASP ZAP can help automate CSRF detection by modifying request headers and analyzing server responses.
API keys in mobile applications face similar risks when the app makes requests from web views or when keys are embedded in JavaScript that runs in hybrid app contexts. The detection approach remains the same: can an attacker trigger state-changing operations without proper anti-CSRF protections?
API Keys-Specific Remediation
Remediating API key CSRF requires implementing protections that make it difficult for attackers to forge valid requests. The most effective approach combines multiple defenses:
1. Move API keys to HttpOnly cookies: This prevents JavaScript from accessing the key, eliminating the primary CSRF vector:
// Server-side cookie setting
const http = require('http');
http.createServer((req, res) => {
res.setHeader('Set-Cookie', [
'apiKey=sk-1234567890abcdef; HttpOnly; Secure; SameSite=Strict',
'csrfToken=abc123; Secure; SameSite=Strict'
]);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Authenticated' }));
}).listen(3000);2. Implement double-submit cookie pattern: Send the API key in a cookie and a matching token in a custom header:
// Client-side request with double-submit
fetch('https://api.target.com/user/profile', {
method: 'POST',
headers: {
'X-CSRF-Token': 'abc123', // Must match cookie value
'Content-Type': 'application/json'
},
credentials: 'include' // Sends HttpOnly cookie
});3. Use custom request headers: Require non-standard headers that attackers cannot easily forge:
// Server-side validation
app.use((req, res, next) => {
if (req.method !== 'GET' && !req.headers['x-custom-api-key']) {
return res.status(403).json({ error: 'Missing custom header' });
}
next();
});4. Implement origin validation: Check the Origin or Referer headers for state-changing requests:
// Middleware to validate request origin
function validateOrigin(req, res, next) {
const allowedOrigins = ['https://yourdomain.com'];
const origin = req.headers.origin || req.headers.referer;
if (req.method !== 'GET' && !allowedOrigins.includes(origin)) {
return res.status(403).json({ error: 'Invalid origin' });
}
next();
}5. Require re-authentication for sensitive operations: Even with API keys, prompt for additional verification before critical changes:
// Two-factor for sensitive changes
app.put('/user/email', (req, res) => {
if (!req.headers['x-2fa-code']) {
return res.status(403).json({
error: 'Two-factor required for email changes',
prompt: 'Enter 2FA code'
});
}
// Validate 2FA code...
});The most robust solution combines HttpOnly cookies with custom headers and origin validation. This multi-layered approach ensures that even if one defense fails, others remain to protect against CSRF attacks on API keys.