Api Key Exposure in Sails with Redis
Api Key Exposure in Sails with Redis
Storing API keys in Redis from a Sails application can expose credentials when configuration and runtime practices are inconsistent. Sails apps often rely on environment variables for secrets, but developers may inadvertently cache or log keys when interacting with Redis data structures. If an attacker can reach the same Redis instance—through misconfigured network rules, weak ACLs, or an exposed management interface—they can read keys stored as strings or within hashes and lists.
Redis does not enforce authentication by default in many deployments, and Sails services connecting to Redis without TLS can leak keys in transit. Additionally, application code that writes full request or debug payloads into Redis sets or streams might include authorization headers or session tokens. Because Redis retains data until explicitly removed or expired, exposed keys persist beyond the immediate request lifecycle. This persistence increases the window for lateral movement if the keys grant access to cloud services or third-party APIs.
The risk is compounded when Sails models or services embed keys in serialized objects stored in Redis. For example, caching user records that contain an apiKey field can expose credentials to anyone who can read that cache key. Even with password-protected Redis, default configurations or weak passwords leave data accessible. Logs from Sails that include Redis command echoes may also print keys if developers inadvertently log full command arguments.
Redis-Specific Remediation in Sails
Remediation focuses on strict configuration, transport security, and disciplined handling of secrets. Use Redis ACLs to restrict commands and keys for the Sails connection user, enforce TLS for all connections, and avoid storing raw API keys in Redis data structures. When caching is necessary, store references or opaque tokens instead of sensitive values, and set reasonable TTLs to limit exposure.
- Enable Redis AUTH and use strong, rotated passwords. Configure Sails to provide the password only via environment variables.
- Require TLS between Sails and Redis to prevent in-transit key exposure.
- Apply least-privilege ACL rules so the Sails Redis user can only perform needed commands (e.g., GET, SET on specific key patterns) and cannot reconfigure the instance.
Concrete Sails/Node Redis examples:
// config/redis.js (Sails custom hook config) or in .env
module.exports.redis = {
host: process.env.REDIS_HOST || '127.0.0.1',
port: parseInt(process.env.REDIS_PORT, 10) || 6379,
password: process.env.REDIS_PASSWORD || '', // set in env, never in code
tls: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: true } : false,
db: 0,
};
// services/RedisService.js — safe usage in Sails
const redis = require('redis');
class RedisService {
constructor() {
this.client = redis.createClient({
socket: {
host: sails.config.redis.host,
port: sails.config.redis.port,
tls: sails.config.redis.tls,
},
password: sails.config.redis.password,
});
this.client.on('error', (err) => {
sails.log.error('Redis connection error:', err);
});
}
// Store a non-sensitive reference; keep the actual key in a vault or env
async setApiReference(apiId, tokenHash) {
await this.client.connect();
await this.client.set(`api:ref:${apiId}`, tokenHash, { EX: 86400 }); // 24h TTL
await this.client.quit();
}
// Retrieve only when necessary and avoid logging
async getApiReference(apiId) {
await this.client.connect();
const token = await this.client.get(`api:ref:${apiId}`);
await this.client.quit();
return token;
}
// Never store raw API keys; if unavoidable, use hashes and strict ACLs
async storeKeyHash(userId, keyHash) {
await this.client.connect();
await this.client.hSet('user:key_hashes', { [userId]: keyHash });
await this.client.expire('user:key_hashes', 604800); // 7 days
await this.client.quit();
}
}
module.exports = new RedisService();
In production, integrate with a secrets manager instead of caching keys in Redis. If you must cache, store hashes or encrypted blobs and rotate keys frequently. Monitor Redis access patterns and audit configuration changes to reduce the likelihood of API key exposure.