Time Of Check Time Of Use with Api Keys
API Keys-Specific Remediation
Remediating TOCTOU vulnerabilities in API key systems requires eliminating the window between validation and use. The most effective approach is atomic operations that combine check and use in a single transaction.
For database-backed API key validation, use row-level locks or atomic transactions:
// Atomic API key validation using database transactions
const validateApiKeyAtomic = async (req, res, next) => {
const apiKey = req.headers['x-api-key'];
try {
// Begin transaction with row lock
await db.query('BEGIN');
// Select key with FOR UPDATE to lock row
const result = await db.query(
'SELECT * FROM api_keys WHERE key = $1 AND active = true FOR UPDATE',
[apiKey]
);
if (!result.rows.length) {
await db.query('ROLLBACK');
return res.status(401).json({ error: 'Invalid API key' });
}
// Use key immediately within transaction
const user = await authenticateWithKey(apiKey);
// Commit transaction
await db.query('COMMIT');
req.user = user;
next();
} catch (error) {
await db.query('ROLLBACK');
return res.status(500).json({ error: 'Internal server error' });
}
};This pattern ensures the key remains valid throughout the entire operation by locking the database row until the transaction completes.
For distributed systems using Redis for API key storage, use Lua scripts for atomic operations:
-- Atomic API key validation Lua script
local key = KEYS[1]
local value = ARGV[1]
local ttl = tonumber(ARGV[2])
-- Check if key exists and is valid
local current = redis.call('GET', key)
if current == false then
return 0 -- Key not found
end
-- Check if key is still valid (timestamp comparison)
local validUntil = tonumber(current)
local now = tonumber(ARGV[3])
if now > validUntil then
return 0 -- Key expired
end
-- Atomically update usage counter
local counterKey = key .. ':counter'
local counter = redis.call('INCR', counterKey)
if counter == 1 then
redis.call('EXPIRE', counterKey, ttl)
end
return counterRate limiting implementations should use Redis's atomic operations:
// Atomic rate limiting with Redis
const checkRateLimitAtomic = async (apiKey) => {
const limit = 100;
const window = 60; // seconds
// Use Redis pipeline for atomic check-and-increment
const pipeline = redis.pipeline();
// Check current count
pipeline.get(`rate:${apiKey}`);
// Perform atomic increment with expiration
pipeline.incr(`rate:${apiKey}`);
pipeline.expire(`rate:${apiKey}`, window);
const [currentCount, incremented, expired] = await pipeline.exec();
// currentCount is the value before increment
if (currentCount >= limit) {
return false;
}
return true;
};For API key rotation scenarios, implement versioned keys with atomic state transitions:
// Atomic key rotation with version validation
const rotateApiKey = async (oldKey, newKey) => {
// Use compare-and-set operation
const result = await redis.eval(
// Lua script for atomic rotation
`local oldKeyVal = redis.call('GET', KEYS[1])
if oldKeyVal == ARGV[1] then
redis.call('SET', KEYS[1], ARGV[2])
return 1
else
return 0
end`,
1, // Number of keys
`api-key:${userId}`,
oldKey,
newKey
);
return result === 1;
};Finally, implement comprehensive logging and monitoring to detect TOCTOU attempts:
// Enhanced logging for TOCTOU detection
const secureApiKeyValidation = async (req, res, next) => {
const apiKey = req.headers['x-api-key'];
const startTime = Date.now();
try {
const validation = await validateApiKeyAtomic(apiKey);
const validationTime = Date.now();
if (!validation.valid) {
logSuspiciousActivity({
type: 'api_key_invalid',
apiKey,
timestamp: startTime,
duration: validationTime - startTime,
ip: req.ip
});
return res.status(401).json({ error: 'Invalid API key' });
}
// Track key usage for anomaly detection
await trackApiKeyUsage({
apiKey,
userId: validation.user.id,
endpoint: req.path,
method: req.method,
timestamp: Date.now()
});
req.user = validation.user;
next();
} catch (error) {
logSecurityError({
type: 'api_key_validation_error',
apiKey,
error: error.message,
timestamp: Date.now()
});
return res.status(500).json({ error: 'Internal server error' });
}
};Frequently Asked Questions
How can I test for API key TOCTOU vulnerabilities in my production environment?
middlebrick which can simulate concurrent API key validation attempts. Monitor for timing discrepancies between validation and usage, and check for successful authentication with keys that were revoked during active sessions. Always test during low-traffic periods and have rollback procedures ready.