Web Security Best Practices — The OWASP Top 10 in Plain English
Security isn't optional#
Every week there's a new breach. Stolen passwords, leaked data, ransomware. Most of these aren't sophisticated attacks — they exploit basic vulnerabilities that could have been prevented.
Here's the OWASP Top 10 in plain English, with practical fixes.
1. Injection (SQL, NoSQL, Command)#
The attacker puts malicious code into your inputs, and your application executes it.
Example: A login form that builds SQL directly:
SELECT * FROM users WHERE email = 'user@email.com' AND password = '' OR '1'='1'
Fix: Use parameterized queries. Never concatenate user input into queries. ORMs handle this automatically — use them.
2. Broken Authentication#
Weak passwords, no rate limiting on login, session tokens that don't expire.
Fixes:
- Enforce strong passwords (min 8 chars, complexity)
- Rate limit login attempts (5 failures → lock for 15 minutes)
- Use bcrypt/scrypt for password hashing (never SHA-256 or MD5)
- Implement MFA for sensitive accounts
- Session tokens expire and rotate on privilege changes
3. Cross-Site Scripting (XSS)#
The attacker injects JavaScript into your page that runs in other users' browsers.
Fix: Escape all user-generated content before rendering. Use frameworks that auto-escape (React, Vue). Set Content-Security-Policy headers. Never use dangerouslySetInnerHTML with user data.
4. Insecure Direct Object References (IDOR)#
User A can access User B's data by changing an ID in the URL: /api/users/123/bank-details → /api/users/124/bank-details.
Fix: Always verify the requesting user has permission to access the resource. Don't rely on obscurity (UUIDs instead of sequential IDs help but aren't sufficient).
5. Security Misconfiguration#
Default passwords, debug mode in production, unnecessary services running, verbose error messages exposing internals.
Fixes:
- Remove default credentials
- Disable debug/development modes in production
- Set security headers (we use X-Content-Type-Options, X-Frame-Options, CSP)
- Don't expose stack traces to users
- Keep dependencies updated
6. Cross-Site Request Forgery (CSRF)#
The attacker tricks a logged-in user into making a request they didn't intend (transferring money, changing email).
Fix: Use CSRF tokens on all state-changing requests. SameSite cookies. Verify the Origin header.
7. Using Components with Known Vulnerabilities#
Your app is secure, but you're using a 3-year-old version of a library with a known exploit.
Fix: Run npm audit regularly. Use Dependabot or Snyk for automated alerts. Update dependencies monthly. Pin versions in production.
8. Insufficient Logging and Monitoring#
You got hacked three months ago and don't know it because nobody was watching.
Fix: Log all authentication events (login, logout, failed attempts). Monitor for anomalies. Set up alerts for unusual patterns. Retain logs for investigation.
9. Server-Side Request Forgery (SSRF)#
The attacker tricks your server into making requests to internal services or cloud metadata endpoints.
Fix: Validate and whitelist URLs before fetching. Block requests to internal IP ranges (10.x, 172.16.x, 169.254.x). Don't let users control the full URL your server fetches.
10. Unvalidated Redirects#
The attacker uses your redirect endpoint to send users to a phishing site: yourapp.com/redirect?url=evil-site.com.
Fix: Whitelist allowed redirect destinations. Don't use user-supplied URLs for redirects. Use relative paths instead of absolute URLs.
The security checklist#
Before going to production:
- HTTPS everywhere (no mixed content)
- Security headers set (CSP, HSTS, X-Frame-Options)
- Passwords hashed with bcrypt
- Rate limiting on auth endpoints
- Input validation on all user data
- SQL/NoSQL injection protection (parameterized queries)
- XSS prevention (auto-escaping, CSP)
- CSRF tokens on state-changing requests
- Dependencies audited and up to date
- Logging for security events
- Secrets in environment variables (never in code)
See security in your architecture#
On Codelit, generate any architecture and click the "Security Audit" tool on any node. It'll identify potential vulnerabilities specific to that component — API gateways, databases, authentication services, and external integrations.
Audit your architecture's security: describe your system on Codelit.io and run one-click security audits on every component.
Explore the GitHub architecture interactively
Try it →Continue learning
Go deeper on security
As an Amazon Associate I earn from qualifying purchases. Codelit may receive a commission at no extra cost to you.
Real-World Cryptography
David Wong · 2021
Which primitive to pick for TLS, JWTs or end-to-end messaging, and what breaks when you pick wrong.
4.7 (100)#14 in Client-Server Networking SystemsThreat Modeling: Designing for Security
Adam Shostack · 2014
The full STRIDE method with checklists and worked diagrams, so you can run a session, not just cite it.
4.5 (357)Release It!
Michael T. Nygard · 2018
Post-mortems of real outages, then the stability patterns (circuit breaker, bulkhead) that stop them.
4.6 (501)#4 in Client-Server Networking SystemsA Philosophy of Software Design
John Ousterhout · 2021
Short book on module depth and complexity, with before/after code showing why an interface is too wide.