Middleware Security Patterns — Complete Implementation Guide
In this tutorial, you will learn about Middleware Security Patterns. We cover key concepts, practical examples, and best practices to help you master this topic.
Middleware security patterns protect your application by filtering, validating, and sanitizing every request before it reaches your business logic, preventing common web attacks at the pipeline level.
What You'll Learn
By the end of this tutorial, you will implement security middleware that prevents SQL injection, XSS Attacks, CSRF Attacks, and request smuggling, and applies security headers to every response.
Why It Matters
Security vulnerabilities in middleware leave your entire application exposed. DodaTech's Durga Antivirus Pro backend uses security middleware to inspect and sanitize all incoming data.
Real-World Use
Durga Antivirus Pro's scan submission API uses security middleware to sanitize filenames, validate file types, limit request sizes, and prevent path traversal attacks before any file is processed.
Security Middleware Learning Path
flowchart LR
A[Performance Middleware] --> B[Security Middleware]
B --> C[Input Sanitization]
B --> D[Attack Prevention]
B --> E{You Are Here}
style E fill:#f90,color:#fff
Input Sanitization Middleware
Input sanitization strips or escapes dangerous characters from request data to prevent injection attacks before they reach your application.
const express = require("express");
const app = express();
app.use(express.json());
function sanitizeInput(req, res, next) {
if (req.body) {
for (const key in req.body) {
if (typeof req.body[key] === "string") {
req.body[key] = req.body[key]
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
}
}
next();
}
app.post("/comment", sanitizeInput, (req, res) => {
res.json({ sanitized: req.body.comment });
});
app.listen(3000);
Expected output for POST /comment with <script>alert('xss')</script>:
{"sanitized": "<script>alert('xss')</script>"}
SQL Injection Prevention
SQL injection middleware inspects query parameters and body fields for SQL patterns and rejects requests that contain them.
const express = require("express");
const app = express();
const SQL_PATTERNS = [
/(\bSELECT\b.*\bFROM\b)/i,
/(\bDROP\b.*\bTABLE\b)/i,
/(\bDELETE\b.*\bFROM\b)/i,
/(\bINSERT\b.*\bINTO\b)/i,
/(\bUNION\b.*\bSELECT\b)/i,
/(--)/,
/(\bOR\b\s+\d+\s*=\s*\d+)/i
];
function preventSQLInjection(req, res, next) {
const checkValue = (value) => {
if (typeof value === "string") {
for (const pattern of SQL_PATTERNS) {
if (pattern.test(value)) {
return true;
}
}
}
return false;
};
const checkObject = (obj) => {
for (const key in obj) {
if (checkValue(obj[key])) return true;
}
return false;
};
if (req.query && checkObject(req.query)) {
return res.status(400).json({ error: "Invalid query parameters" });
}
if (req.body && checkObject(req.body)) {
return res.status(400).json({ error: "Invalid request body" });
}
next();
}
app.use(express.json());
app.use(preventSQLInjection);
app.get("/users", (req, res) => {
res.json({ users: [] });
});
app.listen(3000);
Expected output for GET /users?name=Robert'); DROP TABLE Students;--:
{"error": "Invalid query parameters"}
CSRF Protection
Cross-Site Request Forgery (CSRF) protection middleware ensures that requests to state-changing endpoints originate from your own frontend, not from malicious sites.
const express = require("express");
const csrf = require("csurf");
const cookieParser = require("cookie-parser");
const app = express();
app.use(cookieParser());
app.use(express.urlencoded({ extended: true }));
const csrfProtection = csrf({ cookie: true });
app.get("/form", csrfProtection, (req, res) => {
res.send(`
<form method="POST" action="/transfer">
<input type="hidden" name="_csrf" value="${req.csrfToken()}">
<input type="text" name="amount">
<button type="submit">Transfer</button>
</form>
`);
});
app.post("/transfer", csrfProtection, (req, res) => {
res.json({ transferred: req.body.amount });
});
app.use((err, req, res, next) => {
if (err.code === "EBADCSRFTOKEN") {
return res.status(403).json({ error: "Invalid CSRF token" });
}
next(err);
});
app.listen(3000);
Common Mistakes
Relying on client-side validation — Client validation is for UX, not security. Always validate and sanitize on the server.
Blacklisting instead of whitelisting — Blocking known bad patterns is fragile. Whitelist allowed patterns for stronger security.
Not limiting request body size — An attacker can send a multi-gigabyte request body and exhaust memory. Set body size limits.
Exposing stack traces in error responses — Stack traces reveal code structure. Return generic error messages to clients.
Not validating Content-Type — An attacker can send JSON to a form endpoint or vice versa. Validate Content-Type matches expectations.
Practice Questions
Why is input sanitization important in middleware? It prevents injection attacks (XSS, SQLi) from reaching business logic, protecting your application and users.
What is the difference between sanitization and validation? Validation rejects invalid data. Sanitization modifies data to make it safe while preserving its meaning.
How does CSRF protection work? It generates a unique token for each form session. The server rejects submissions without a valid token.
Challenge: Build middleware that detects and blocks path traversal attacks in file paths.
function preventPathTraversal(req, res, next) {
const path = req.query.file || req.body.file;
if (path && (path.includes("..") || path.includes("/"))) {
return res.status(400).json({ error: "Invalid path" });
}
next();
}
FAQ
Mini Project
Build a comprehensive security middleware pipeline with input sanitization, SQL injection prevention, Rate Limiting, secure headers, and request size limiting.
const express = require("express");
const helmet = require("helmet");
const rateLimit = require("express-rate-limit");
const app = express();
app.use(helmet());
app.use(express.json({ limit: "1mb" }));
const limiter = rateLimit({
windowMs: 60000,
max: 100,
message: { error: "Too many requests" }
});
app.use(limiter);
function sanitize(req, res, next) {
if (req.body) {
for (const key in req.body) {
if (typeof req.body[key] === "string") {
req.body[key] = req.body[key].replace(/<[^>]*>/g, "");
}
}
}
next();
}
app.post("/submit", sanitize, (req, res) => {
res.json({ received: req.body });
});
app.listen(3000);
What's Next
Now that you understand middleware security, apply everything in the comprehensive middleware project. Then explore rate limiting patterns in depth.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro