Listen to this Post

Introduction:
APIs are the backbone of modern applications, yet they remain one of the most attacked entry points. While many developers focus on functionality, security often takes a back seat—until a breach occurs. This article dissects seven common API security mistakes, provides step‑by‑step remediation techniques, and equips you with the tools and commands to harden your backend effectively.
Learning Objectives:
- Identify and fix critical API security flaws beyond basic authentication.
- Implement server‑side validation, rate limiting, and proper data exposure controls.
- Use practical commands and code examples to audit and secure your API in real‑world scenarios.
You Should Know:
1. JWT: Authentication Is Not Authorization
Many developers assume that using JSON Web Tokens (JWT) makes their API secure. However, JWT only verifies identity—it does not enforce what a user is allowed to do. If you are not validating roles and permissions on every protected endpoint, a low‑privilege user could escalate access by simply replaying a valid token.
Step‑by‑step guide:
- Issue: A token may contain a role claim (
admin: false), but the backend does not check it. - Fix: Implement an authorization middleware that inspects the token’s payload and verifies permissions against your database or a policy.
Node.js (Express) example:
// authMiddleware.js
const jwt = require('jsonwebtoken');
module.exports = function authorize(requiredRole) {
return (req, res, next) => {
const token = req.headers.authorization?.split(' ')[bash];
if (!token) return res.status(401).json({ error: 'No token provided' });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Verify role from database (do not trust token alone if roles can change)
const user = db.findUserById(decoded.userId);
if (user.role !== requiredRole) {
return res.status(403).json({ error: 'Insufficient privileges' });
}
req.user = user;
next();
} catch (err) {
res.status(401).json({ error: 'Invalid token' });
}
};
};
Test with curl:
Obtain a token (e.g., for a regular user)
curl -X POST https://api.example.com/login -d '{"username":"user","password":"pass"}' -H "Content-Type: application/json"
Try to access admin endpoint with that token
curl -X GET https://api.example.com/admin -H "Authorization: Bearer <user_token>"
Expected: 403 Forbidden
2. Trusting the Frontend Blindly
Never assume that data coming from the client is safe. Relying on `userId` from the request body, or an `isAdmin` flag sent by the frontend, invites privilege escalation and data tampering.
Step‑by‑step guide:
- Identify trust violations: Search your codebase for any place where a sensitive field (e.g.,
role,userId,isAdmin) is read directly from the request body without server‑side context. - Fix: Always derive the authenticated user’s identity from the session or token, and validate that any resource access belongs to that user.
Example (vulnerable code):
app.post('/update-profile', (req, res) => {
const { userId, email } = req.body; // userId taken from client!
db.updateUser(userId, { email });
});
Secure version:
app.post('/update-profile', authorize(), (req, res) => {
const { email } = req.body;
// userId comes from authenticated token (set by authorize middleware)
db.updateUser(req.user.id, { email });
});
3. No Rate Limiting
Without rate limiting, your API is exposed to brute‑force attacks, credential stuffing, and denial‑of‑service. A simple rate limiter can block the majority of low‑effort attacks.
Step‑by‑step guide:
- Implement rate limiting using a middleware like
express-rate-limit. - Configure limits based on endpoint sensitivity (e.g., stricter for login, looser for public reads).
Node.js (Express) example:
const rateLimit = require('express-rate-limit');
const loginLimiter = rateLimit({
windowMs: 15 60 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
message: 'Too many login attempts, please try again later.'
});
app.use('/login', loginLimiter);
Testing with curl (simulate rapid requests):
for i in {1..10}; do curl -X POST https://api.example.com/login -d '{"username":"test","password":"wrong"}' -H "Content-Type: application/json"; done
After 5 attempts, you should receive a `429 Too Many Requests` response.
4. Poor Input Validation
Relying solely on frontend validation is a recipe for disaster. Malformed payloads can trigger NoSQL injection, cause crashes, or bypass business logic.
Step‑by‑step guide:
- Use a schema validation library (Joi, Zod, or express-validator) to enforce expected data types and formats.
- Always validate on the server, regardless of frontend checks.
Example with Zod:
const { z } = require('zod');
const userSchema = z.object({
email: z.string().email(),
age: z.number().min(18).max(120)
});
app.post('/register', (req, res) => {
try {
const validated = userSchema.parse(req.body);
// Proceed with validated data
} catch (err) {
res.status(400).json({ error: err.errors });
}
});
Test NoSQL injection attempt:
curl -X POST https://api.example.com/users -d '{"email": {"$ne": null}, "password": "hacked"}' -H "Content-Type: application/json"
With proper validation, this payload should be rejected before hitting the database.
5. Storing Sensitive Data Incorrectly
Plain‑text passwords, hardcoded secrets, and tokens without expiration are self‑inflicted wounds. Attackers love these oversights.
Step‑by‑step guide:
- Hash passwords using a strong algorithm (bcrypt, Argon2).
- Store secrets in environment variables or a secrets manager (e.g., HashiCorp Vault).
- Set short expiration times for tokens and implement refresh token rotation.
Password hashing example (Node.js with bcrypt):
const bcrypt = require('bcrypt');
const saltRounds = 10;
async function hashPassword(plainPassword) {
return await bcrypt.hash(plainPassword, saltRounds);
}
async function comparePassword(plainPassword, hash) {
return await bcrypt.compare(plainPassword, hash);
}
Generate a strong secret:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Add this to your `.env` file and never commit it.
6. Exposing Too Much Data
Returning full user objects—including password hashes, internal IDs, and admin flags—leaks information that can aid an attacker.
Step‑by‑step guide:
- Use response mapping to filter out sensitive fields.
- In MongoDB, use `.select(‘-password -__v’)` to exclude fields.
- In REST APIs, create dedicated response DTOs (Data Transfer Objects).
Example with Mongoose:
// Instead of: const user = await User.findById(id);
// Use:
const user = await User.findById(id).select('-password -resetToken');
Or using a helper function:
function sanitizeUser(user) {
const { password, ...safeUser } = user.toObject();
return safeUser;
}
Test with curl:
curl https://api.example.com/users/123 The response should not contain any sensitive fields.
7. No Monitoring
If you don’t log and monitor API activity, you won’t know you’re under attack until it’s too late. Anomaly detection and alerts are essential.
Step‑by‑step guide:
- Implement structured logging (e.g., Winston, Morgan) to capture requests, errors, and unusual patterns.
- Set up alerts for suspicious activities (multiple failed logins, high traffic from a single IP).
- Integrate with monitoring tools like Prometheus, Grafana, or cloud‑native solutions.
Basic logging with Morgan (Node.js):
npm install morgan
const morgan = require('morgan');
app.use(morgan('combined')); // Logs in Apache combined format
Check logs for anomalies:
tail -f /var/log/api/access.log | grep " 401 " Monitor unauthorized attempts
Set up a simple alert (cron job + curl):
!/bin/bash COUNT=$(grep "$(date --date='5 min ago' '+%Y-%m-%dT%H:%M')" /var/log/api/access.log | grep " 401 " | wc -l) if [ $COUNT -gt 100 ]; then curl -X POST https://alerts.example.com -d 'message=High number of 401 errors' fi
What Undercode Say:
- Security is a mindset, not a middleware: The most robust API can be undone by assuming the client is honest or neglecting to validate permissions on every route.
- Shift left: Integrate security checks early—during code reviews, with automated testing, and by using static analysis tools to catch common flaws before deployment.
- Continuous monitoring is non‑negotiable: Without visibility, you are flying blind. Invest in logging and anomaly detection to detect breaches in progress and respond swiftly.
Prediction:
As APIs become the primary interface for applications, attackers will increasingly weaponize AI to automate vulnerability discovery. Future API security will rely on machine learning models that detect behavioral anomalies in real time, coupled with automated policy enforcement (e.g., Open Policy Agent). Developers who adopt a “security by design” approach now will be better prepared for this intelligent threat landscape.
▶️ Related Video (84% Match):
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Lovely Sinha – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


