secure-headers-kit
v1.2.0
Published
Easily apply secure HTTP headers, rate limiting (memory + Redis), and protection to your Express app.
Maintainers
Readme
secure-headers-kit
Secure, safe HTTP headers middleware for Express applications with built-in rate limiting. Protect your web applications with essential security headers and request throttling out of the box.
Features
- 🛡️ Secure by default - Applies essential security headers automatically
- 🚦 Built-in rate limiting - Memory and Redis-based request throttling
- ⚡ Zero dependencies - Lightweight and fast (Redis optional)
- 🔧 Customizable - Override or add custom headers as needed
- 🔒 Strict mode - Prevent accidental override of critical security headers
- 📊 Optional logging - Debug and monitor header application and rate limits
- 📦 Easy integration - Simple Express middleware
Installation
npm install secure-headers-kitFor Redis rate limiting:
npm install secure-headers-kit redisQuick Start
const express = require("express");
const { applySecureHeaders } = require("secure-headers-kit");
const app = express();
// Apply secure headers with defaults
app.use(applySecureHeaders());
app.get("/", (req, res) => {
res.send("Hello, secure world!");
});
app.listen(3000);Default Headers
The middleware applies the following security headers by default:
| Header | Value | Purpose |
| --------------------------- | ---------------------------------------------- | ---------------------------------------------------- |
| Content-Security-Policy | default-src 'self' | Prevents XSS attacks by controlling resource loading |
| Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | Enforces HTTPS connections |
| X-Content-Type-Options | nosniff | Prevents MIME type sniffing |
| X-Frame-Options | DENY | Prevents clickjacking attacks |
| Referrer-Policy | no-referrer | Controls referrer information sharing |
| Permissions-Policy | camera=(), microphone=(), geolocation=() | Restricts browser features |
Configuration
Basic Usage
// Use all default headers
app.use(applySecureHeaders());Custom Headers
// Override or add custom headers
app.use(
applySecureHeaders({
overrides: {
"Content-Security-Policy": "default-src 'self' 'unsafe-inline'",
"X-Custom-Header": "custom-value",
},
})
);Enable Logging
// Enable logging to see applied headers and rate limit events
app.use(
applySecureHeaders({
logging: true,
})
);Strict Mode
// Prevent accidental override of critical security headers
app.use(
applySecureHeaders({
strict: true,
overrides: {
"Content-Security-Policy": "malicious-policy", // This will be ignored
"X-Custom-Header": "safe-value", // This will be applied
},
})
);Rate Limiting
Memory-based Rate Limiting
// Basic memory-based rate limiting (60 requests per minute)
app.use(
applySecureHeaders({
rateLimit: {
windowMs: 60 * 1000, // 1 minute
maxRequests: 60,
message: "Too many requests, please try again later.",
},
})
);Redis-based Rate Limiting
const redis = require("redis");
const client = redis.createClient();
app.use(
applySecureHeaders({
rateLimit: {
type: "redis",
redisClient: client,
windowMs: 60 * 1000, // 1 minute
maxRequests: 100,
keyPrefix: "api:ratelimit:",
message: "Rate limit exceeded",
},
})
);Custom Rate Limit Handler
app.use(
applySecureHeaders({
rateLimit: {
windowMs: 15 * 60 * 1000, // 15 minutes
maxRequests: 100,
onLimitExceeded: (req, res) => {
res.status(429).json({
error: "Rate limit exceeded",
retryAfter: "15 minutes",
timestamp: new Date().toISOString(),
});
},
},
})
);API Reference
applySecureHeaders(options?)
Creates Express middleware that applies secure HTTP headers and optional rate limiting.
Parameters
options(Object, optional)overrides(Object, optional) - Custom headers to override or addstrict(boolean, optional, default:false) - Prevent overriding critical headerslogging(boolean, optional, default:false) - Enable console loggingrateLimit(Object, optional) - Rate limiting configuration
Rate Limit Options
windowMs(number, default:60000) - Time window in millisecondsmaxRequests(number, default:60) - Maximum requests per windowmessage(string, default:"Too many requests. Please try again later.") - Error messagetype(string, default:"memory") - Storage type:"memory"or"redis"keyPrefix(string, default:"shk:") - Redis key prefixredisClient(Object, required for Redis) - Redis client instanceonLimitExceeded(Function, optional) - Custom handler for rate limit exceeded
Returns
Express middleware function (req, res, next) => void
Examples
Production API with Redis Rate Limiting
const express = require("express");
const redis = require("redis");
const { applySecureHeaders } = require("secure-headers-kit");
const app = express();
const redisClient = redis.createClient({
host: process.env.REDIS_HOST || "localhost",
port: process.env.REDIS_PORT || 6379,
});
app.use(
applySecureHeaders({
strict: true,
logging: process.env.NODE_ENV === "development",
overrides: {
"Content-Security-Policy": "default-src 'none'; frame-ancestors 'none';",
"X-API-Version": "1.0.0",
},
rateLimit: {
type: "redis",
redisClient,
windowMs: 15 * 60 * 1000, // 15 minutes
maxRequests: 1000,
keyPrefix: "api:v1:",
onLimitExceeded: (req, res) => {
res.status(429).json({
error: "API rate limit exceeded",
limit: 1000,
window: "15 minutes",
retryAfter: new Date(Date.now() + 15 * 60 * 1000).toISOString(),
});
},
},
})
);Different Rate Limits for Different Routes
// Global rate limiting
app.use(
applySecureHeaders({
rateLimit: {
windowMs: 60 * 1000,
maxRequests: 60,
},
})
);
// Stricter rate limiting for auth endpoints
app.use(
"/auth",
applySecureHeaders({
rateLimit: {
windowMs: 15 * 60 * 1000, // 15 minutes
maxRequests: 5, // Only 5 auth attempts per 15 minutes
message: "Too many authentication attempts",
},
})
);Content Security Policy Configuration
app.use(
applySecureHeaders({
overrides: {
"Content-Security-Policy": [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"font-src 'self' https://fonts.gstatic.com",
"img-src 'self' data: https:",
].join("; "),
},
})
);Development vs Production
const isDevelopment = process.env.NODE_ENV === "development";
app.use(
applySecureHeaders({
logging: isDevelopment,
overrides: {
"Content-Security-Policy": isDevelopment
? "default-src 'self' 'unsafe-inline' 'unsafe-eval'"
: "default-src 'self'",
},
rateLimit: isDevelopment
? undefined
: {
windowMs: 60 * 1000,
maxRequests: 100,
},
})
);Rate Limiting Details
Memory Storage
- Stores rate limit data in application memory
- Resets when application restarts
- Suitable for single-instance applications
- No external dependencies
Redis Storage
- Persistent rate limiting across application restarts
- Suitable for multi-instance/clustered applications
- Requires Redis server
- Automatic key expiration
IP Address Detection
The middleware detects client IP addresses in the following order:
X-Forwarded-Forheader (first IP)req.ipreq.connection.remoteAddress
Security Considerations
- Content Security Policy: The default CSP is restrictive. Customize it for your application's needs.
- Strict Transport Security: Only use HSTS if you're serving over HTTPS.
- Frame Options:
DENYprevents all framing. UseSAMEORIGINif you need to embed your pages. - Rate Limiting: Choose appropriate limits based on your application's expected traffic.
- Redis Security: Secure your Redis instance with authentication and network restrictions.
- Regular Updates: Keep your security headers up to date with current best practices.
Critical Headers
The following headers are considered critical and cannot be overridden in strict mode:
Content-Security-PolicyStrict-Transport-SecurityX-Content-Type-OptionsX-Frame-OptionsReferrer-PolicyPermissions-Policy
Performance Considerations
- Memory rate limiting has O(1) lookup time
- Redis rate limiting adds network latency but provides persistence
- Consider using Redis for production applications with multiple instances
- Rate limit cleanup for memory storage happens automatically during requests
Troubleshooting
Common Issues
Rate limiting not working:
- Ensure the middleware is applied before your routes
- Check if
req.ipis properly populated (you might needapp.set('trust proxy', true))
Redis connection errors:
- Verify Redis server is running and accessible
- Check Redis client configuration and credentials
Headers not applied:
- Ensure middleware is added before routes
- Check for conflicting middleware that might override headers
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details.
Related Resources
Changelog
See CHANGELOG.md for version history and updates.
