HTTP Deep Dive: Headers, Cookies & CORS

Master HTTP/HTTPS internals — request/response structure, security headers, cookie attributes, Same-Origin Policy, CORS, and how attackers exploit each.

Easy 55m 3 tasks

Learning Objectives

  • Dissect HTTP requests and responses with all relevant headers
  • Explain Same-Origin Policy and why browsers enforce it
  • Configure CORS correctly and identify misconfigurations
  • Set all security headers: CSP, HSTS, X-Frame-Options, etc.
  • Identify security issues in cookie attributes

HTTP Request Anatomy

POST /api/login HTTP/1.1
Host: example.com
Content-Type: application/json
Authorization: Bearer eyJhbGci...
Cookie: session=abc123; csrf=xyz
User-Agent: Mozilla/5.0 ...
Referer: https://example.com/login
Origin: https://example.com
Content-Length: 42

{"username": "alice", "password": "secret"}

HTTP Response Anatomy

HTTP/1.1 200 OK
Content-Type: application/json
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self'
Strict-Transport-Security: max-age=31536000; includeSubDomains
Cache-Control: no-store

{"user": "alice", "role": "admin"}

Same-Origin Policy (SOP)

The browser's core security model:

Origin = scheme + host + port
https://example.com:443  — distinct from each:
http://example.com:80    (different scheme AND port)
https://sub.example.com  (different host)
https://example.com:8443 (different port)

SOP rules:
- JS can send requests cross-origin (images, scripts, forms)
- JS cannot read cross-origin responses without CORS permission
- Cookies are sent to their domain but JS on other origins can't read them

CORS – Cross-Origin Resource Sharing

CORS lets servers relax SOP for specific origins:

-- Request (JS on https://app.com fetching https://api.com/data)
GET /data HTTP/1.1
Origin: https://app.com

-- Server response (CORS headers)
Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization

CORS Preflight (for non-simple requests)

-- Browser sends OPTIONS before the actual request
OPTIONS /api/data HTTP/1.1
Origin: https://app.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

-- Server must respond to approve
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400

CORS Misconfigurations (Critical!)

# VULNERABLE 1: Reflect any origin
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true  # INVALID — browsers reject this combo

# VULNERABLE 2: Reflect attacker origin without validation
origin = request.headers.get("Origin")
response.headers["Access-Control-Allow-Origin"] = origin   # ANY origin allowed!
response.headers["Access-Control-Allow-Credentials"] = "true"
# Attacker from evil.com can read your API responses as the victim user

# VULNERABLE 3: Weak origin validation
if origin.endswith(".example.com"):  # bypassed by: attacker-example.com
    allow(origin)

if "example.com" in origin:          # bypassed by: evil-example.com.attacker.com
    allow(origin)

# CORRECT: exact allowlist
ALLOWED_ORIGINS = {"https://app.example.com", "https://admin.example.com"}
if origin in ALLOWED_ORIGINS:
    response.headers["Access-Control-Allow-Origin"] = origin
    response.headers["Vary"] = "Origin"

Security Headers

Content-Security-Policy (CSP)

# Block all external resources (strict)
Content-Security-Policy: default-src 'self'

# Allow scripts from self + specific CDN, no inline
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'

# Unsafe directives (avoid):
script-src 'unsafe-inline'    # allows inline <script> — defeats XSS protection
script-src 'unsafe-eval'      # allows eval() — dangerous
script-src *                  # allows any origin — useless

# Nonce-based CSP (allows specific inline scripts):
Content-Security-Policy: script-src 'nonce-r4nd0m'
<script nonce="r4nd0m">/* allowed */</script>

HSTS

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  • Forces HTTPS for 1 year (max-age=31536000)
  • includeSubDomains — applies to all subdomains
  • preload — submit to browser preload lists (always HTTPS before first visit)

Other Security Headers

X-Frame-Options: DENY                         # no iframing (clickjacking)
X-Content-Type-Options: nosniff               # no MIME sniffing
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin

Cookie Security Attributes

Set-Cookie: session=abc123;
    HttpOnly;           # JS cannot read — prevents XSS theft
    Secure;             # HTTPS only
    SameSite=Strict;    # No cross-site — prevents CSRF
    Path=/;
    Domain=example.com;
    Max-Age=3600        # 1 hour (expires=absolute date alternative)

SameSite values:
  Strict — cookie never sent on cross-site requests
  Lax    — sent on top-level GET navigations (links), not POST
  None   — sent on all cross-site requests (requires Secure)

Cookie Attack Vectors

Missing HttpOnly  XSS can steal: document.cookie
Missing Secure    sent over HTTP  MITM sniffing
SameSite=None     CSRF possible (if no CSRF token)
No expiry         session never expires
Broad Domain      subdomain.example.com can steal cookie

HTTP/2 and HTTP/3

HTTP/1.1: text-based, one request per connection (keep-alive)
HTTP/2:   binary, multiplexed streams, header compression (HPACK)
HTTP/3:   UDP-based (QUIC), faster connection setup

Security notes:
- HTTP/2 header injection via pseudo-headers
- HTTP request smuggling differs between HTTP/1.1 and HTTP/2
- HTTP/3 QUIC reduces MITM opportunity

curl for Web Security Testing

# Send custom headers
curl -H "Origin: https://evil.com" -v https://api.target.com/data

# See full request/response headers
curl -v https://example.com/login

# POST JSON
curl -X POST https://api.example.com/login     -H "Content-Type: application/json"     -d '{"user":"admin","pass":"admin"}'

# Follow redirects, show headers
curl -L -D headers.txt https://example.com

# Check security headers
curl -I https://example.com | grep -iE "(strict|content-security|frame|content-type|referrer)"

# Test CORS
curl -H "Origin: https://evil.com"      -H "Access-Control-Request-Method: GET"      -X OPTIONS -v https://api.target.com/sensitive

Using curl or securityheaders.com: (1) check 5 websites for security headers, (2) document which headers are missing on each, (3) identify sites with CORS * wildcard, (4) find a site with SameSite=None without a CSRF token, (5) write a Django middleware that adds all recommended security headers.

✦ Answer the questions to complete this task

What does Strict-Transport-Security: max-age=31536000 tell the browser?

Why is Access-Control-Allow-Origin: * combined with Allow-Credentials: true rejected by browsers?

Set up a Flask API that reflects the Origin header without validation. Then: (1) demonstrate that a page from evil.com can read the API response, (2) add proper origin allowlist validation, (3) verify evil.com can no longer read the response, (4) add Vary: Origin header and explain why it's needed for caching.

✦ Answer the questions to complete this task

Why must you add Vary: Origin when setting per-origin CORS headers?

For a web app that: loads jQuery from code.jquery.com, has inline CSS, uses Google Fonts, has a /report endpoint for CSP violations — write a strict CSP header. Then test it with CSP Evaluator (csp-evaluator.withgoogle.com). Document any bypass risks in your policy.

✦ Answer the questions to complete this task

What is a CSP report-uri / report-to directive?

💪 Exercises & Challenges

📝 MCQ Medium +20 XP

HTTP & Headers MCQ

HTTP & Headers MCQ

Start →
⚙️ Practical Medium +30 XP

Security Header Middleware

Security Header Middleware

Start →
🚩 Challenge Hard +50 XP

CORS Misconfiguration Exploit

CORS Misconfiguration Exploit

Start →