Security Is Everyone's Responsibility
Web security is not just the concern of a dedicated security team. Every developer who writes code that handles user input, stores data, or communicates over a network is making security decisions. Understanding the most common vulnerabilities and how to prevent them is a fundamental part of building professional web applications.
The OWASP Top 10 provides a regularly updated list of the most critical web application security risks. Familiarizing yourself with these categories gives you a practical framework for thinking about security in your daily work.
Cross-Site Scripting (XSS)
XSS occurs when an attacker injects malicious scripts into content that other users view. There are three main types: stored XSS, reflected XSS, and DOM-based XSS. All of them exploit the browser's trust in content served from your domain.
The primary defense against XSS is output encoding. Always encode user-supplied data before inserting it into HTML, JavaScript, CSS, or URLs. Modern frameworks like React, Vue, and Angular encode output by default, but you must be careful when using escape hatches like dangerouslySetInnerHTML or v-html.
// Dangerous: inserting raw HTML element.innerHTML = userInput; // Safe: using text content element.textContent = userInput;
Implement a Content Security Policy (CSP) header as an additional layer of defense. A well-configured CSP prevents the execution of inline scripts and restricts which domains can serve resources to your page.
SQL Injection
SQL injection happens when user input is concatenated directly into SQL queries, allowing attackers to modify the query's logic. Despite being well-understood, it remains one of the most common and dangerous vulnerabilities.
// Vulnerable: string concatenation
const query = `SELECT * FROM users WHERE id = ${userId}`;
// Safe: parameterized query
const query = "SELECT * FROM users WHERE id = $1";
const result = await db.query(query, [userId]);
Always use parameterized queries or an ORM that handles parameterization for you. Never build SQL strings by concatenating user input.
Cross-Site Request Forgery (CSRF)
CSRF attacks trick authenticated users into submitting requests to your application without their knowledge. If a user is logged into your site and visits a malicious page, that page can submit forms or make requests that execute with the user's session.
Mitigations include:
- Use anti-CSRF tokens that are validated on every state-changing request
- Set the
SameSiteattribute on cookies toStrictorLax - Verify the
OriginorRefererheader on incoming requests - Require re-authentication for sensitive operations
Authentication Best Practices
Authentication is a critical security boundary. Getting it wrong exposes your users and their data.
- Never store passwords in plain text. Use bcrypt, scrypt, or Argon2 for hashing
- Implement rate limiting on login endpoints to prevent brute-force attacks
- Support multi-factor authentication for sensitive applications
- Use secure, HttpOnly, SameSite cookies for session management
- Set reasonable session expiration times and provide a way for users to invalidate sessions
Security Headers
HTTP security headers add important protections with minimal effort:
- Content-Security-Policy restricts which resources the browser can load
- Strict-Transport-Security ensures the browser always uses HTTPS
- X-Content-Type-Options: nosniff prevents MIME type sniffing
- X-Frame-Options or CSP
frame-ancestorsprevents clickjacking - Referrer-Policy controls how much referrer information is shared
Configure these headers at the server or CDN level so they apply to every response. Tools like SecurityHeaders.com can audit your configuration and identify missing protections.
Staying Informed
Security is an evolving field. Subscribe to security advisories for your dependencies, run npm audit regularly, and keep your packages up to date. Consider adding static analysis tools like Semgrep or CodeQL to your CI pipeline to catch common vulnerability patterns automatically.