Ssrf with Api Keys
How SSRF Manifests in API Keys
Server-Side Request Forgery (SSRF) in API key contexts creates unique attack vectors that target how applications handle external requests using credentials. Unlike traditional SSRF attacks that focus on network reconnaissance or internal service access, API key SSRF specifically exploits the trust relationship between your application and external services.
The most common pattern involves an attacker manipulating API endpoints to make the server fetch resources from unexpected locations. When API keys are involved, the attack becomes more dangerous because the server acts as a trusted client, potentially exposing sensitive data or abusing service quotas.
Consider this vulnerable pattern in Node.js:
app.post('/fetch-data', async (req, res) => {
const url = req.body.url;
const apiKey = process.env.EXTERNAL_API_KEY;
// Vulnerable: No validation of user-supplied URL
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
res.json(await response.json());
});An attacker could supply http://localhost:8080/internal or http://169.254.169.254/latest/meta-data/ (AWS metadata service) as the URL parameter. The server, using the legitimate API key, would make authenticated requests to internal services that shouldn't be publicly accessible.
Cloud metadata service SSRF is particularly dangerous because it often contains IAM roles, temporary credentials, and configuration data. A successful attack might reveal:
{
"Code" : "Success",
"LastUpdated" : "2024-01-15T10:20:30Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIAXXXXXXXXXXXXXXXX",
"SecretAccessKey" : "",
"Token" : "",
"Expiration" : "2024-01-15T16:30:00Z"
} Another manifestation involves DNS rebinding attacks where the attacker controls DNS resolution timing. The server resolves a hostname to a legitimate IP initially, but the attacker changes DNS records mid-attack to point to internal IPs like 127.0.0.1 or 10.0.0.1.
Service abuse through SSRF is also common. An attacker might make your server repeatedly call paid API endpoints, exhausting your API key quota or incurring unexpected costs. For example:
// Malicious URL targeting paid translation API
const maliciousUrl = 'https://translation.googleapis.com/language/translate/v2?key=YOUR_KEY&q=...';The server, using your valid API key, makes expensive requests that appear legitimate to the external service but are actually initiated by an attacker exploiting your SSRF vulnerability.
API Keys-Specific Detection
Detecting SSRF vulnerabilities in API key contexts requires both static analysis and dynamic testing. The key is identifying where user input flows into URL construction or external service calls without proper validation.
Static analysis should flag these patterns:
// Red flags in code review
const url = req.query.url; // User input used directly
const endpoint = buildUrl(userInput); // Dynamic URL construction
const client = new ExternalServiceClient(key, userInput); // User input in client configDynamic testing involves attempting to access restricted resources through the API. Effective test cases include:
| Test Case | Target | Expected Behavior |
|---|---|---|
| Localhost access | 127.0.0.1, localhost | Blocked or timeout |
| Private IP ranges | 10.x.x.x, 172.16-31.x.x, 192.168.x.x | Blocked |
| Metadata services | 169.254.169.254 (AWS), 169.254.169.254 (Azure) | Blocked |
| Domain bypass | localhost.example.com, 127.0.0.1.example.com | Blocked |
middleBrick's black-box scanning approach is particularly effective for SSRF detection because it tests the actual runtime behavior without requiring source code access. The scanner attempts requests to known SSRF targets and analyzes responses to determine if the server is vulnerable.
For API key-specific SSRF, middleBrick tests:
- Whether the API accepts URLs that resolve to internal services
- If authentication headers are properly scoped and don't leak credentials
- Whether the service properly handles malformed or deceptive URLs
- If rate limiting and quota enforcement work correctly under SSRF conditions
The scanner also checks for common SSRF bypasses like:
// Bypass attempts to test
http://[::]:80@127.0.0.1/
http://0/ (octal notation)
http://127.1 (missing octet)
http://localhost.localdomain
http://0x7F.0.0.1 (hexadecimal)Network-level detection includes monitoring for unexpected outbound connections from your API servers and analyzing DNS query patterns for suspicious resolution attempts.
API Keys-Specific Remediation
Effective SSRF prevention in API key contexts requires defense in depth. Start with input validation and URL sanitization before any external request is made.
URL validation should be strict and whitelist-based:
const isValidUrl = (url) => {
try {
const parsed = new URL(url);
// Block private IP ranges
const privateRanges = [
/^127\./, // Loopback
/^10\./, // Class A private
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // Class B private
/^192\.168\./, // Class C private
/^169\.254\./, // Link-local
/^0\.0\.0\.0/, // Default route
];
if (privateRanges.some(regex => regex.test(parsed.hostname))) {
return false;
}
// Block metadata services
if (parsed.hostname === '169.254.169.254') {
return false;
}
// Only allow specific protocols
if (!['http:', 'https:'].includes(parsed.protocol)) {
return false;
}
return true;
} catch (e) {
return false;
}
};
// Usage
app.post('/fetch-data', async (req, res) => {
const url = req.body.url;
if (!isValidUrl(url)) {
return res.status(400).json({ error: 'Invalid URL' });
}
// Safe to proceed
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${process.env.EXTERNAL_API_KEY}` }
});
res.json(await response.json());
});For Node.js applications, consider using the safe-url library or implementing a request proxy that validates all outbound connections:
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer({});
app.use('/api/proxy', (req, res) => {
const targetUrl = req.query.url;
if (!isValidUrl(targetUrl)) {
return res.status(400).json({ error: 'URL blocked by security policy' });
}
proxy.web(req, res, { target: targetUrl });
});
// Network-level firewall rules
// Block all outbound except to approved services
const approvedServices = [
'api.example.com',
'api.stripe.com',
'api.aws.amazon.com'
];
// In production, use iptables or cloud security groups:
// iptables -A OUTPUT -d 10.0.0.0/8 -j DROP
// iptables -A OUTPUT -d 172.16.0.0/12 -j DROP
// iptables -A OUTPUT -d 192.168.0.0/16 -j DROPAPI key management is crucial for SSRF mitigation. Use scoped API keys that limit what services can be accessed:
// Instead of one master key, use scoped keys
const SCOPED_API_KEYS = {
'translation': 'sk-translate-...', // Only translation API
'payment': 'sk-payment-...', // Only payment processing
'analytics': 'sk-analytics-...' // Only analytics
};
// Map API key to allowed services
const keyScopes = {
'sk-translate-...': ['translation.googleapis.com'],
'sk-payment-...': ['api.stripe.com'],
'sk-analytics-...': ['api.mixpanel.com']
};
function validateKeyScope(key, targetService) {
const allowedServices = keyScopes[key];
return allowedServices?.includes(targetService) || false;
}
// During SSRF testing, verify that even if SSRF occurs, the key can't access unauthorized servicesImplement timeout and circuit breaker patterns to limit SSRF damage:
const axios = require('axios');
const { CircuitBreaker } = require('opossum');
const breaker = new CircuitBreaker(axios.get, {
timeout: 5000, // 5 second timeout
errorThresholdPercentage: 50,
resetTimeout: 30000
});
breaker.on('timeout', () => {
console.warn('SSRF attempt timed out');
});
breaker.on('fallback', () => {
console.warn('SSRF circuit breaker triggered');
});
app.post('/fetch-data', async (req, res) => {
const url = req.body.url;
if (!isValidUrl(url)) {
return res.status(400).json({ error: 'Invalid URL' });
}
try {
const result = await breaker.fire(url);
res.json(result.data);
} catch (error) {
res.status(503).json({ error: 'Service unavailable' });
}
});Finally, implement comprehensive logging and monitoring for SSRF attempts. Track failed validation attempts, blocked requests, and unusual outbound traffic patterns. Set up alerts for repeated SSRF test patterns that might indicate active exploitation attempts.
Related CWEs: ssrf
| CWE ID | Name | Severity |
|---|---|---|
| CWE-918 | Server-Side Request Forgery (SSRF) | CRITICAL |
| CWE-441 | Unintended Proxy or Intermediary (Confused Deputy) | HIGH |