Security Best Practices
Ship a Node service that resists the attacks it will actually face in production
- stop injection (SQL and OS command) with parameterization instead of string building;
- prevent XSS by encoding output and enforcing a Content-Security-Policy;
- keep secrets out of source, logs, and error responses;
- recognise and block prototype pollution in object merges and JSON parsing;
- harden HTTP with helmet, throttle abuse with rate limiting, and audit your dependencies.
1. Defense in depth: never trust one wall
Every request from the internet is untrusted input until proven otherwise. A robust service does not rely on a single check; it applies overlapping controls so that one mistake does not become a breach. This is defense in depth: validation at the edge, safe data access in the middle, and least-privilege everywhere.
Analogy. A castle does not survive because of one thick door. It has a moat, an outer wall, an inner wall, and guards at the keep. If an attacker slips past one, the next still stops them. Your rate limiter, validator, parameterized query, and security headers are those concentric walls.
The diagram below shows a request passing through the layers of a hardened Express app. Each band is an independent control; a payload must defeat all of them to cause harm.
Keep one rule in mind throughout: never build a security decision from data the client fully controls. Validate it, escape it, or bind it — but do not concatenate it into something powerful.