Web Security - Protecting Your Web Applications from Common Attacks
Web security is a critical concern for every web application. Vulnerabilities can lead to data breaches, user account compromises, and legal consequences.
The OWASP (Open Web Application Security Project) Top 10 lists the most critical web application security risks that every developer should be aware of.
This guide covers the most common web security vulnerabilities and practical strategies to prevent them in your applications.
Cross-Site Scripting (XSS)
XSS attacks inject malicious scripts into web pages viewed by other users. Attackers can steal cookies, session tokens, or redirect users to malicious sites.
// VULNERABLE - Never inject raw user input into DOM
document.getElementById('output').innerHTML = userInput;
// SAFE - Use textContent instead of innerHTML
document.getElementById('output').textContent = userInput;
// SAFE - Escape HTML characters on the server
function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// Use a Content Security Policy header
// Content-Security-Policy: default-src 'self'; script-src 'self'
Use frameworks like React that auto-escape content by default, and always set a strict Content Security Policy (CSP) header on your server.
Cross-Site Request Forgery (CSRF)
CSRF tricks authenticated users into submitting requests they didn't intend to make. An attacker's website can trigger actions on your site using the victim's session.
// Install: npm install csurf
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
// Add CSRF token to forms
app.get('/form', csrfProtection, (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
// Validate on POST
app.post('/submit', csrfProtection, (req, res) => {
res.json({ status: 'ok' });
});
// For APIs: Use SameSite cookie attribute
res.cookie('sessionId', token, {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
SQL Injection Prevention
SQL injection occurs when untrusted data is sent to a database interpreter as part of a command. Always use parameterized queries or prepared statements.
// VULNERABLE - Never do this
const query = `SELECT * FROM users WHERE email = '${userEmail}'`;
// SAFE - Use parameterized queries
const { rows } = await pool.query(
'SELECT * FROM users WHERE email = $1',
[userEmail]
);
// SAFE - Mongoose (MongoDB) auto-sanitizes
const user = await User.findOne({ email: userEmail });
// SAFE - Sequelize with parameterized query
const user = await User.findOne({ where: { email: userEmail } });
Security HTTP Headers
Proper HTTP response headers can prevent many common attacks. Use the helmet package in Express to set secure headers automatically.
const helmet = require('helmet');
app.use(helmet()); // Sets multiple security headers at once
// Includes:
// - Content-Security-Policy
// - X-Frame-Options: DENY (prevents clickjacking)
// - X-Content-Type-Options: nosniff
// - Strict-Transport-Security (HSTS)
// - Referrer-Policy
// - Permissions-Policy
Web Security Checklist
- Always use HTTPS with a valid SSL/TLS certificate
- Hash passwords with bcrypt, Argon2, or scrypt — never store plain text
- Implement rate limiting on login and API endpoints
- Validate and sanitize all user inputs on the server side
- Use parameterized queries for all database operations
- Set secure, httpOnly, and SameSite flags on cookies
- Implement proper CORS configuration to restrict allowed origins
- Keep dependencies updated and audit with npm audit regularly
- Never expose stack traces or detailed error messages to users
Conclusion
Web security requires a layered approach — no single technique is enough. By understanding common vulnerabilities like XSS, CSRF, and SQL injection, you can design defenses at every layer of your application.
Make security a core part of development from the start, not an afterthought. Regularly audit dependencies, follow OWASP guidelines, and keep your infrastructure updated.
Codecrown