This content originally appeared on HackerNoon and was authored by Mohit Menghnani
Security Things That Matter
Security is dull & boring until you get hacked. Then it's REALLY interesting. Node is great at making it easy to create APIs overnight, but that also makes it easy to do it wrong.
\ I have seen others get compromised because of:
- They employed packages they never audited (npm is wonderful & frightening)
- They rely on input from users (never, EVER do that)
- They hard-code credentials directly into the code (why in the world?)
\ I am sure you have wondered what you'd do if someone hacked your app. Let’s look at some suggestions to avoid getting hacked.
The Basics
Check What Users/Customers Send You
Always expect users to attempt strange things. Check ALL OF IT.
\
// Bad code
app.post('/users', (req, res) => {
db.users.create(req.body); // Accepting whatever users send? Bad idea!
});
// Better approach
app.post('/users', (req, res) => {
// Use something like Joi or express-validator
if (!req.body.email || !req.body.email.includes('@')) {
return res.status(400).send('Invalid email');
}
if (typeof req.body.age !== 'number') {
return res.status(400).send('Age must be a number');
}
// Now it's safer to save
db.users.create(req.body);
});
\ I found this out for myself when someone crashed my application by placing an emoji within the username field. Fun times.
Login Stuff: Don't Mess This Up
JWT tokens are cool but simple to get wrong. Here's my take:
\
// Creating tokens - keep them short lived!
const token = jwt.sign(
{ userId: user.id },
process.env.JWT_SECRET,
{ expiresIn: '1h' } // Dont make these last forever
);
// Check tokens on protected routes
function checkAuth(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).send('Login required');
}
try {
const user = jwt.verify(token, process.env.JWT_SECRET);
req.user = user; // Add user info to request
next();
} catch (err) {
return res.status(403).send('Invalid or expired token');
}
}
// Use it to protect routes
app.get('/profile', checkAuth, (req, res) => {
// Only logged in users get here
});
\ Auth has two halves: ensuring that the user is who they say they are (authentication) and ensuring that they can do what they're trying to do (authorization). \n
Never, under any circumstances, commit your database password to GitHub
\
// NO NO NO - don't hardcode passwords!!
const db = mysql.connect({
host: 'mydatabase.server.com',
user: 'admin',
password: 'SuperSecret123!' // This should never be in your code
});
// Do this instead
require('dotenv').config();
const db = mysql.connect({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD
});
\ And DO NOT forget to place your .env file to .gitignore.
Real Security Problems I've Seen
SQL Injection Still Works?! Yes, it does. And it is so easy to stop:
\
// Dangerous - allows SQL injection
app.get('/users', (req, res) => {
const name = req.query.name;
db.query(`SELECT * FROM users WHERE name = '${name}'`, // BAD!
(err, results) => res.json(results)
);
});
// Safe - use parameters
app.get('/users', (req, res) => {
const name = req.query.name;
db.query('SELECT * FROM users WHERE name = ?',
[name], // This prevents SQL injection
(err, results) => res.json(results)
);
});
\ When someone attempts ?name=x'; DROP TABLE users; -- you will be happy you utilized parameters.
\
Too Many Requests = Crashed Server
The app crashed when a user abused the search API too much. Implement rate limiting:
\
const rateLimit = require('express-rate-limit');
// Basic protection for all routes
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit per IP
});
app.use(limiter);
// Extra protection for login attempts
const loginLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 hour
max: 5 // 5 login attempts per hour
});
app.use('/login', loginLimiter);
\
Old Packages = Security Holes
Most hacks happen through outdated packages. Check yours:
# Run this often!
npm audit
# Fix what you can
npm audit fix
\
Use Helmet for HTTP Headers
One line of code that fixes several issues:
const helmet = require('helmet');
app.use(helmet()); // Adds security headers
FAQs that every Developer should know
Q: What do you need to fix first that is most important?
A: Input validation. Most attacks start there.
\ Q: What is the best way to know if my API security is sufficient?
A: Have someone attempt to break it. Or you can try a tool like OWASP ZAP.
\ Q: How can I prevent security vulnerabilities caused by dependencies? \n A: Schedule a calendar event to update your dependencies in a timely manner. To detect these vulnerabilities, consider using tools like npm audit, snyk, or dependable.
\ Q: What is the best way to know if my API security is sufficient?
A: Have someone attempt to break it. Or you can try a tool like OWASP ZAP.
Final Thoughts - Lessons to learn from
Security is not an afterthought - it should be built into the code from the outset.
\ Start with these basics:
- Authenticate all users
- Secure your auth routes
- Store Secrets in Environment Variables
- Update dependencies
- Set rate limits
- Always use HTTPS
\ So, which gap will you be closing today?
\
This content originally appeared on HackerNoon and was authored by Mohit Menghnani

Mohit Menghnani | Sciencx (2025-03-04T07:10:05+00:00) The Developer’s Guide to Bulletproof API Security in Node.js. Retrieved from https://www.scien.cx/2025/03/04/the-developers-guide-to-bulletproof-api-security-in-node-js/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.