@neabyte/express-shield
v1.0.1
Published
Express Middleware With Rate-Limit And Security Headers
Maintainers
Readme
🛡️ @neabyte/express-shield
Lightweight Express middleware for rate limiting, unique client fingerprinting, Cloudflare-aware IP trust, and essential security headers 🛡️
Now with auto-updated Cloudflare IP lists, hot-reload without restart, and zero dependency design for production-grade security and flexibility.
✨ Features
- 🔁 Auto-updated Cloudflare IPs: Automatically keeps the IP whitelist in sync with Cloudflare’s official ranges (IPv4/IPv6) and hot-reloads without restart.
- 🚦 Rate Limiting: Configurable time window and maximum requests per IP address (with Cloudflare trusted IP logic).
- 🔒 Fingerprinting: Generates a unique, consistent client fingerprint for better request tracking.
- 🛡️ Security Headers: Automatically applies crucial HTTP security headers (
X-Content-Type-Options,Strict-Transport-Security,X-Frame-Options,Referrer-Policy, and more). - 🎨 Custom Error Responses: Override default 429 (Too Many Requests) handler with custom logic/format.
- 📦 Modular Design: Redis is optional; rate limiting is skipped if no Redis is supplied.
- ⚙️ TypeScript Support: Built-in
.d.tstypes, fully typed exports. - 🔄 Zero External Dependency: No deps except Express and (optionally) ioredis for rate-limit.
🚀 Installation
npm install @neabyte/express-shieldRequires Node.js >=18.20.8
- After install, Cloudflare IPs are fetched to
data/folder. - To update manually:
node ./script/update-cloudflare-ip.js
🛠️ Quick Start
With Redis (Enables Rate Limiting)
const express = require('express')
const Redis = require('ioredis')
const { createExpressShield } = require('@neabyte/express-shield')
const app = express()
const redisClient = new Redis()
app.use(
createExpressShield(
redisClient,
{
app,
windowSec: 60,
maxRequests: 10,
showHeader: true,
showLog: false,
applySecurity: true,
customErrorResponse: (req, res, ttl) => {
res.status(429).json({
error: 'Too many requests',
ip: req.fingerprint.ip,
retryAfterSec: ttl
})
}
}
)
)
app.get('/', (req, res) => {
res.send('Hello, world! 🎉 This route is protected with rate limiting and security headers.')
})
app.listen(3000, () => console.log('Server running on port 3000 🚀'))Without Redis (Skips Rate Limiting)
const express = require('express')
const { createExpressShield } = require('@neabyte/express-shield')
const app = express()
app.use(
createExpressShield(
null,
{
app,
applySecurity: true
}
)
)
app.get('/', (req, res) => {
res.send('Hello, world! 🎉 This route is protected with security headers.')
})
app.listen(3000, () => console.log('Server running on port 3000 🚀'))⚡ Cloudflare IP Support
The IP whitelist used for trusting
cf-connecting-ipis auto-updated using Cloudflare’s published range.After install, files
data/cloudflare_ipv4.jsonanddata/cloudflare_ipv6.jsonare created/updated.IPs are hot-reloaded at runtime (no restart needed).
To force reload in app code:
const { reloadCloudflareIpList } = require('@neabyte/express-shield') reloadCloudflareIpList()
🧩 Parameters & Defaults
| Parameter | Type | Default | Description |
| ----------------------------- | --------- | -------------------- | -------------------------------------------------------------- |
| redisClient | object? | null | Optional ioredis instance. If falsy, disables rate limiting. |
| options.app | Express | null | Express app instance for header patching. |
| options.windowSec | number | 60 | Duration of the rate limit window (seconds). |
| options.maxRequests | number | 10 | Max allowed requests per IP within the window. |
| options.showHeader | boolean | true | Show X-Fingerprint-Id header. |
| options.showLog | boolean | false | Enable debug console logging. |
| options.applySecurity | boolean | true | Apply HTTP security headers. |
| options.customErrorResponse | function | default 429 JSON | Custom 429 handler. (req, res, ttl) => void |
| options.whitelist | string[] | [] | Skip rate-limit for these IPs. |
| options.ipResolver | function | getClientIpAddress | Custom IP resolver (rarely needed). |
📖 API Reference
createExpressShield(redisClient, options)
Creates the Express middleware. Handles security headers, fingerprinting, rate limit (if Redis provided).getClientIpAddress(req)
Returns the trusted client IP. Automatically checkscf-connecting-ipif request comes from Cloudflare IP range.generateFingerprintHash(req)
Returns a SHA256 hash of client IP + headers (used for fingerprinting).reloadCloudflareIpList()
Forces reload of Cloudflare IPv4 + IPv6 lists fromdata/folder. Useful for manual reload or custom schedulers.watchCloudflareIpList()
Starts file watcher. Automatically reloads Cloudflare IPs whendata/cloudflare_ipv4.jsonordata/cloudflare_ipv6.jsonchange.CLOUDFLARE_IPV4/CLOUDFLARE_IPV6
Exposes current trusted Cloudflare IP lists (arrays of CIDR).checkIpInCidrList(ip, cidrList)
Utility to check if an IP (IPv4/IPv6) is within any CIDR in the list.checkIpv4InCidr(ip, cidr)/checkIpv6InCidr(ip, cidr)
Low-level CIDR match utilities for IPv4 / IPv6.convertIpv4ToNumber(ip)/convertIpv6ToBigint(ip)
Internal helpers to convert IP addresses for CIDR math (exposed for testability).
Note: All utility functions are exposed primarily for testing and advanced use cases.
Typical users only needcreateExpressShieldand optionallyreloadCloudflareIpList.
✅ Running Tests Locally
npm install
npm test❤️ Contributing
- Fork the repo 🔱
- Create your feature branch (
git checkout -b feature/your-feature-name) - Commit your changes (
git commit -am 'Add some your-feature-name') - Push to the branch (
git push origin feature/your-feature-name) - Open a Pull Request 📬
📬 Questions / Support
For questions, issues or feature requests, please open an issue or start a discussion.
🗒️ Changelog
See CHANGELOG.md for all updates.
📜 License
MIT License © 2025 NeaByteLab
