Tags: security, owasp, auth, cryptography, nodejs, typescript, web
Level: intermediate
TL;DR: Best practices, defensive coding patterns, and checklist to prevent OWASP Top 10 vulnerabilities during development.
Never trust client input: validate format, length, and types on the server.
Treat data crossing trust boundaries as untrusted by default.
Use parameterized queries or ORMs to eliminate SQL and NoSQL injection risks.
Context-aware output encoding prevents Cross-Site Scripting (XSS).
Use argon2 or bcrypt with appropriate work factors for hashing passwords.
Implement least privilege on system accounts, API tokens, and database roles.
Enforce secure session cookies: HttpOnly, Secure, and SameSite=Strict or Lax.
Implement robust centralized authentication and authorization checks per route.
Avoid security through obscurity: use proven, vetted cryptographic libraries.
Prevent denial of service with rate limiting and payload size limits.
Q: How do you prevent SQL injection in modern backend services?R: I always enforce parameterized queries or use typed ORM/query builders like Prisma or Knex. Never concatenate user strings into raw SQL execution buffers.
Q: What is the difference between authorization and authentication?R: Authentication verifies identity (who you are), while authorization verifies permissions (what resources or actions you are allowed to access).
Q: How do you protect a Single Page Application against XSS attacks?R: I rely on frameworks that escape templates by default, sanitize dynamic HTML with libraries like DOMPurify, and enforce a strict Content Security Policy (CSP).
Q: Where should sensitive data like secrets and API keys be stored?R: Never in source control. I inject them at runtime using environment variables managed via secret managers like AWS Secrets Manager or HashiCorp Vault.
Q: How do you defend against Cross-Site Request Forgery (CSRF)?R: I use anti-CSRF tokens for state-changing endpoints, enforce SameSite=Strict or SameSite=Lax cookies, and authenticate mutating APIs via Bearer tokens.
Storing passwords in plain text or using outdated hashing functions like MD5 or SHA-1.
Insecure Direct Object References (IDOR): querying records by client-supplied ID without verifying ownership.
Concatenating user input directly into file system paths, enabling path traversal attacks (../).
Disabling CORS or using wildcard Access-Control-Allow-Origin: * alongside credentials.
Leaking stack traces, system paths, or internal metadata in API production error responses.
Re-inventing custom encryption schemes instead of using standard AES-GCM or authenticated primitives.
// Parameterized SQL query using pg / node-postgres
import { Pool } from 'pg';
const pool = new Pool();
async function getUserById(userId: string) {
const query = 'SELECT id, email, created_at FROM users WHERE id = $1';
const { rows } = await pool.query(query, [userId]);
return rows[0] || null;
}
TypeScript
// Password hashing with Argon2
import argon2 from 'argon2';
async function hashPassword(plainText: string): Promise<string> {
return argon2.hash(plainText, {
type: argon2.argon2id,
memoryCost: 2 ** 16,
timeCost: 3,
parallelism: 1
});
}
TypeScript
// Safe file path resolution preventing directory traversal
import path from 'node:path';
function resolveSafePath(baseDir: string, userFilename: string): string {
const safeFilename = path.basename(userFilename);
const targetPath = path.resolve(baseDir, safeFilename);
if (!targetPath.startsWith(path.resolve(baseDir))) {
throw new Error('Access denied: directory traversal attempt');
}
return targetPath;
}
[ ] Review OWASP Top 10 latest standard updates
[ ] Audit dependency vulnerability scanners (npm audit, Snyk, Trivy) in CI/CD pipeline
[ ] Verify Content Security Policy headers across frontend routes
[x] Enforce parameterized queries across all database drivers
[x] Configure secure session flags (HttpOnly, Secure, SameSite)
OWASP Top 10 Web Application Security Risks
OWASP Cheat Sheet Series
CWE (Common Weakness Enumeration) Top 25 Most Dangerous Software Weaknesses