OptStuff

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

LayerProtects AgainstHow
Encrypted StorageDatabase breachesAES-256-GCM encryption for secret keys at rest
Request SigningUnauthorized usageHMAC-SHA256 signature on every request
Signature ExpirationReplay attacksOptional exp timestamp limits URL validity
Domain AllowlistsHotlinking & abuseTwo-layer domain control
Rate LimitingResource exhaustionPer-key per-minute and per-day limits
Dual-Key SystemAccidental exposureSeparates 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

AttackProtection
Brute ForceHMAC-SHA256 + 32-char signature makes collision infeasible
Replay AttacksSignature expiration (exp) limits URL validity
Timing AttackstimingSafeEqual constant-time comparison
Database BreachAES-256-GCM encryption; keys useless without master key
Man-in-the-MiddleHTTPS + signature validation
HotlinkingReferer domain allowlist
Unauthorized SourcesSource domain allowlist
Resource ExhaustionPer-key rate limiting that fails closed when Redis is unavailable
SSRFSource URL validation, DNS/IP safety checks, pinned upstream fetches, and redirect rejection (details)

Secure Defaults

SettingEmpty/Unset Behavior
allowedSourceDomainsProduction: reject all requests
allowedRefererDomainsAllow all (no restriction)
API key expirationNo expiration (we recommend setting one)

Technical Standards

StandardUsage
AES-256-GCMAuthenticated encryption for stored keys
HKDF (RFC 5869)Cryptographic key derivation
HMAC-SHA256URL signature generation
Constant-time comparisonTiming-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.local files added to .gitignore
  • API key expiration set for non-permanent integrations
  • Unused or test keys revoked

Domain Security

  • allowedSourceDomains explicitly configured (empty list rejects all in production)
  • allowedRefererDomains configured 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 exp expiration 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:

EnvironmentProjectAPI KeySource Domains
Developmentmy-app-devDev key (short expiry)Empty (allows all)
Stagingmy-app-stagingStaging keySame as production
Productionmy-appProduction keyExplicitly 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:

  1. Rotate immediately — Use the Rotate action in Dashboard → API Keys. This atomically revokes the old key and creates a new one.
  2. Update environment variables — Deploy the new secret key to all services that use it.
  3. Review request logs — Check Dashboard → Usage for suspicious traffic patterns during the exposure window.
  4. Audit access — Verify no unauthorized domains were added to the project's domain security settings.
  5. 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.

Last updated on

On this page