The golden rule of web security: never trust the client. The browser is entirely under the user’s control. Users can manipulate JavaScript, edit cookies, forge headers, and bypass client-side validation. Every security check that matters must happen on the server.
Cross-Site Scripting (XSS)
XSS lets an attacker inject malicious scripts into content served from a website you trust. When another user visits that page, their browser runs the attacker’s script — not realizing it wasn’t put there by the site itself. The classic kill chain looks like this:- The injected script reads
document.cookie(which contains the user’s session ID). - The script sends that data to an attacker-controlled server.
- The attacker uses the stolen session ID to hijack the victim’s logged-in session.
- Reflected XSS
- Stored XSS
- DOM-based XSS
The malicious script travels in the URL and is immediately “reflected” back in the server’s response — for example, in a search result or error message. The attacker crafts a link and tricks the victim into clicking it.Example URL:The server echoes the query parameter into the HTML response. If the output is not encoded, the script executes in the victim’s browser.
XSS mitigations
| Defense | How it helps |
|---|---|
| Context-aware output encoding | Convert < → <, > → >, & → & before inserting user input into HTML. This prevents the browser from interpreting the content as code. |
| HttpOnly cookies | Prevents JavaScript from reading session cookies even if XSS runs. |
| Content Security Policy (CSP) | Whitelists allowed script sources. A strict CSP blocks inline scripts and external scripts from untrusted domains. |
Avoid innerHTML | Use textContent when inserting untrusted data into the DOM. textContent never parses HTML. |
SQL Injection (SQLi)
SQLi happens when user input is concatenated directly into an SQL query instead of being treated as data. The attacker escapes the string context and appends their own SQL commands. Vulnerable code:Alice → query becomes SELECT * FROM users WHERE name = 'Alice'
Attacker input: ' OR '1'='1 → query becomes:
users table, bypassing the login check entirely. More destructive payloads can drop tables, exfiltrate data, or in some configurations execute OS commands.
SQLi mitigations
Use parameterized queries (prepared statements). The database treats user input strictly as data, never as executable SQL:- Apply the least privilege principle — your app’s database user should not have
DROP,CREATE, or administrative rights it doesn’t need. - Use an ORM (Object-Relational Mapper); most provide parameterization by default.
- Validate and sanitize input to reject unexpected characters before they reach the database layer.
Insecure Direct Object References (IDOR)
IDOR is a surprisingly common access control failure. The application uses a user-supplied identifier (typically in a URL or request body) to look up a resource — but never verifies whether the requesting user is authorized to access that specific resource. Example: You log in and your profile page is at:10050 to 10051 in the URL. If the server returns another student’s grades, that is an IDOR vulnerability. The server authenticated you, but it never checked whether resource 10051 belongs to you.
Mitigations:
- Always verify server-side that the authenticated user owns or is authorized to access the requested object. Never rely on the client to enforce this.
- Use UUIDs or other non-sequential, hard-to-guess identifiers instead of integers. Sequential IDs make enumeration trivial.
- Implement a consistent authorization layer that every endpoint must pass through.
Broken authentication
Broken authentication refers to flaws in login and session management that let attackers compromise accounts or bypass access controls without knowing the correct credentials. Common mistakes:- Weak password policies — allowing short, all-lowercase, dictionary-word passwords gives attackers easy brute-force targets.
- No lockout mechanism — without rate limiting or lockouts, an attacker can try millions of passwords automatically.
- Session IDs in URLs — URLs appear in server logs, browser history, and Referer headers. A session ID in the URL leaks the session to anyone who can see those logs.
- Require multi-factor authentication (MFA) — a stolen password alone is not enough to log in.
- Use well-established authentication libraries and frameworks rather than building your own. Don’t roll your own cryptography.
- Store session IDs in HttpOnly, Secure, SameSite cookies — never in the URL.
- Enforce account lockouts after a configurable number of failed attempts.
- Enforce strong password complexity and minimum length requirements.
OWASP Top 10
The Open Web Application Security Project (OWASP) publishes a list of the most critical web application security risks, updated every few years. The 2025 list reflects the current threat landscape:| Rank | Category |
|---|---|
| A01:2025 | Broken Access Control |
| A02:2025 | Security Misconfiguration |
| A03:2025 | Software Supply Chain Failures |
| A04:2025 | Cryptographic Failures |
| A05:2025 | Injection |
| A06:2025 | Insecure Design |
| A07:2025 | Authentication Failures |
| A08:2025 | Software or Data Integrity Failures |
| A09:2025 | Logging & Alerting Failures |
| A10:2025 | Mishandling of Exceptional Conditions |
Rank does not mean frequency — it reflects impact. Broken Access Control sits at #1 not because it is the most common bug, but because the consequences of getting it wrong are severe. Use the OWASP Top 10 as a design checklist, not just a remediation list.
- Defense in depth — layer your security controls. If the firewall fails, authentication must hold. If authentication fails, input validation must hold.
- Least privilege — services, database accounts, and users should have only the permissions they actually need.
- Reduce the attack surface — fewer features means fewer vulnerabilities.
- Log and alert — you need to know when an attack is happening, or reconstruct what happened after the fact.