Security Best Practices
Defense-in-depth security overview — encrypted storage, request signing, domain allowlists, rate limiting, and actionable recommendations.
OptStuff is built with a defense-in-depth approach. Even if one layer is compromised, multiple additional barriers protect your assets.
Security Layers
| Layer | Protects Against | How |
|---|---|---|
| Encrypted Storage | Database breaches | AES-256-GCM encryption for secret keys at rest |
| Request Signing | Unauthorized usage | HMAC-SHA256 signature on every request |
| Signature Expiration | Replay attacks | Optional exp timestamp limits URL validity |
| Domain Allowlists | Hotlinking & abuse | Two-layer domain control |
| Rate Limiting | Resource exhaustion | Per-key per-minute and per-day limits |
| Dual-Key System | Accidental exposure | Separates public identifiers from secrets |
Encrypted Storage
Secret keys are encrypted with AES-256-GCM before storage. The encryption key is derived via HKDF (RFC 5869) from a master secret stored in environment variables — separate from the database. Even if the database is compromised, attackers cannot obtain usable keys.
Request Signing
Every request must include an HMAC-SHA256 signature. The signature is a one-way function — intercepting it cannot reveal the secret key. Signatures are compared using constant-time comparison (timingSafeEqual) to prevent timing attacks.
See URL Signing for implementation details.
Signature Expiration
The optional exp parameter limits how long a signed URL is valid. Recommended expiration times depend on the use case — see URL Signing.
Domain Allowlists
Two-layer domain control restricts both who can use the service (referer domains) and which images can be processed (source domains). Both settings are configured at the project level in Settings → Domain Security. If allowedRefererDomains is configured, requests without a matching Referer are denied; leave it empty for server-to-server or privacy-stripping clients. See Domain Allowlists for configuration and Referer Security Model for the trust model.
Rate Limiting
Per-key rate limits prevent abuse and contain the impact of compromised keys. In the current implementation, Redis outages cause rate limiting to fail closed with 503 to protect expensive image processing and quota integrity. Monitor Redis health and alerting accordingly. See Rate Limiting for details.
Dual-Key System
Public keys (pk_...) are safe to expose in URLs. Secret keys (sk_...) never leave your server. Even if someone sees a signed URL, they cannot forge new requests.
Attack Protection Summary
| Attack | Protection |
|---|---|
| Brute Force | HMAC-SHA256 + 32-char signature makes collision infeasible |
| Replay Attacks | Signature expiration (exp) limits URL validity |
| Timing Attacks | timingSafeEqual constant-time comparison |
| Database Breach | AES-256-GCM encryption; keys useless without master key |
| Man-in-the-Middle | HTTPS + signature validation |
| Hotlinking | Referer domain allowlist |
| Unauthorized Sources | Source domain allowlist |
| Resource Exhaustion | Per-key rate limiting that fails closed when Redis is unavailable |
| SSRF | Source URL validation, DNS/IP safety checks, pinned upstream fetches, and redirect rejection (details) |
Secure Defaults
| Setting | Empty/Unset Behavior |
|---|---|
allowedSourceDomains | Production: reject all requests |
allowedRefererDomains | Allow all (no restriction) |
| API key expiration | No expiration (we recommend setting one) |
Technical Standards
| Standard | Usage |
|---|---|
| AES-256-GCM | Authenticated encryption for stored keys |
| HKDF (RFC 5869) | Cryptographic key derivation |
| HMAC-SHA256 | URL signature generation |
| Constant-time comparison | Timing-safe signature verification |
Production Checklist
Use this checklist before going live:
API Key Security
- Secret keys (
sk_...) stored in server-side environment variables only - No secret keys in frontend code, Git, or client-side bundles
-
.env/.env.localfiles added to.gitignore - API key expiration set for non-permanent integrations
- Unused or test keys revoked
Domain Security
-
allowedSourceDomainsexplicitly configured (empty list rejects all in production) -
allowedRefererDomainsconfigured if browser hotlinking is a concern - Development, staging, and production use separate projects or domain configs
URL Signing
- All signing happens server-side (Server Components, API Routes, or backend services)
- Appropriate
expexpiration set on signed URLs - No signing logic in client-side JavaScript
Infrastructure
- Redis health monitoring configured
- Rate limit alerts set (see Rate Limiting)
- HTTPS enforced on all endpoints
Environment Isolation
Use separate projects and API keys for each environment to prevent cross-environment leakage:
| Environment | Project | API Key | Source Domains |
|---|---|---|---|
| Development | my-app-dev | Dev key (short expiry) | Empty (allows all) |
| Staging | my-app-staging | Staging key | Same as production |
| Production | my-app | Production key | Explicitly listed |
This ensures a compromised development key cannot access production resources, and development traffic does not consume production rate limits.
Incident Response: Key Compromise
If an API key may have been exposed:
- Rotate immediately — Use the Rotate action in Dashboard → API Keys. This atomically revokes the old key and creates a new one.
- Update environment variables — Deploy the new secret key to all services that use it.
- Review request logs — Check Dashboard → Usage for suspicious traffic patterns during the exposure window.
- Audit access — Verify no unauthorized domains were added to the project's domain security settings.
- Consider expiration — For the new key, set a shorter expiration until you've confirmed the incident is contained.
Rotation is atomic — the old key stops working the moment the new key is created. Plan for a brief window where in-flight requests with the old key may fail.
Related Documentation
- URL Signing — Signature generation and code examples
- Domain Allowlists — Domain configuration
- Rate Limiting — Rate limit configuration
- Key Management — API key lifecycle best practices
- SSRF Prevention — How the image proxy prevents Server-Side Request Forgery
Last updated on