
After a decade building and maintaining APIs, I've learned that security isn't a feature; it's a fundamental requirement. However, insecure APIs can expose sensitive data and become main targets for cyberattacks.
We've all seen APIs that were rushed into production without sufficient security tests.
// Vulnerable API (Express)
app.get('/users/:id', (req, res) => {
// Directly using user input
const userId = req.params.id;
db.query(`SELECT * FROM users WHERE id = ${userId}`, (err, data) => {
if (err) {
return res.status(400).send('Bad Request');
}
res.json(data);
});
});
This code is vulnerable to SQL injection. Attackers can manipulate the userId parameter to inject malicious SQL code.
Input Validation and Sanitization:
Validate all user input: Never trust user input.
Sanitize input: Escape or remove potentially harmful characters.
Use parameterized queries: Prevent SQL injection.
// Improved example with parameterized queries
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
db.query('SELECT * FROM users WHERE id = ?', [userId], (err, data) => {
if (err) {
// Handle error
}
res.json(data);
});
});
Authentication and Authorization:
Use OAuth 2.0, JWT, etc
Implement role-based access control
Don't expose sensitive information in URLs: Use headers or request bodies.
// Example with JWT authentication (Express)
const jwt = require('jsonwebtoken');
function validateUserWithToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}
app.get('/dashboard', validateUserWithToken, (req, res) => {
// ... protected resource ...
res.json({ message: 'Protected data' });
});
HTTPS and TLS
Always use HTTPS: Encrypt communication between clients and servers.
Use strong TLS configurations: Disable weak ciphers.
Rate Limiting and Throttling:
Prevent DDoS attacks: Limit the number of requests from a single IP address.
Protect against brute-force attacks: Limit login attempts.
Logging and Monitoring:
Log all API requests and responses: Include timestamps, IP addresses, and user agents.
Monitor API performance and security: Use tools like Splunk.
Set up alerts for suspicious activity: Unusual traffic patterns, failed login attempts, etc.
Regular Security Audits
Conduct regular security audits to identify vulnerabilities.
Perform penetration testing to simulate real-world attacks.
No single technique is foolproof. It's about layering security measures to minimize the attack surface.
