Web Security: Browser, HTTP, and Sessions

Understand methods, status codes, headers, cookies, origins, redirects, caching, content types, and proxies.

9.1 HTTP security basics

Understand methods, status codes, headers, cookies, origins, redirects, caching, content types, and proxies. HTTPS protects traffic in transit but does not automatically provide correct authorization or safe browser behavior.

9.2 Security headers

Configure headers appropriate to the app and test them in deployment:

Content-Security-Policy (CSP): limits permitted resource sources and helps mitigate XSS impact; it is not a substitute for safe rendering.

Strict-Transport-Security (HSTS): tells browsers to use HTTPS for a domain after receiving the policy securely.

X-Content-Type-Options: nosniff: reduces MIME-type confusion.

Referrer-Policy: controls referrer information.

Permissions-Policy: restricts selected browser features.

Frame protection: use CSP frame-ancestors for modern clickjacking defense, with legacy headers only as compatibility requires.

Headers must be configured with the application's origins, deployment topology, and required integrations in mind.

Try it: header and cookie checker Paste a response's headers (or load a sample) and the checker reports which protections are present, which are missing or weak, and why. It parses text only — nothing is fetched.

9.3 Secure cookies

For session cookies, consider:

Secure: send only over HTTPS.

HttpOnly: prevent ordinary JavaScript from reading the cookie.

SameSite: restrict some cross-site sending behavior.

Narrow Domain and Path scope.

Short, risk-appropriate lifetime and server-side revocation.

Cookie attributes do not eliminate XSS, CSRF, or authorization bugs.

Building a hardened session cookie Output (CPython 3.13.1):

Secure keeps the cookie off plain HTTP, HttpOnly hides it from page scripts, SameSite=Lax stops it being sent on most cross-site subrequests, and Max-Age bounds its life in the browser — the server must still be able to revoke the session.

from http.cookies import SimpleCookie
import secrets

cookie = SimpleCookie()
cookie["session"] = secrets.token_urlsafe(32)
morsel = cookie["session"]
morsel["secure"] = True
morsel["httponly"] = True
morsel["samesite"] = "Lax"
morsel["path"] = "/"
morsel["max-age"] = 3600

header = cookie.output(header="Set-Cookie:")
name_value, *attributes = header.split("; ")
print("Set-Cookie: session=<random value>;", "; ".join(attributes))
Set-Cookie: session=<random value>; HttpOnly; Max-Age=3600; Path=/; SameSite=Lax; Secure

9.4 CORS

Cross-Origin Resource Sharing tells browsers which origins may read responses through browser cross-origin APIs. It is not authentication and is not a universal firewall. Use explicit trusted origins, carefully manage credentialed requests, and avoid reflecting arbitrary origins. Do not combine credentialed requests with a wildcard origin.

9.5 Clickjacking and UI redressing

Use CSP frame-ancestors to specify whether the application may be embedded. Sensitive confirmation screens should make the action and destination clear.

9.6 Cache and information leakage

Set appropriate cache directives for private or sensitive responses. Shared caches must not serve one user's response to another. Avoid putting tokens, passwords, and sensitive personal data in URLs because URLs may be recorded in logs, browser history, analytics, and referrer headers.

9.7 Redirects and URL handling

Use allowlisted destination identifiers or validated relative paths for redirects. Do not redirect blindly to arbitrary user-supplied URLs after login or payment actions.

Validating a post-login redirect Output (CPython 3.13.1):

Only relative paths under known prefixes survive; absolute URLs, scheme-relative //host forms and backslash variants (which some browsers treat as //) fall back to a fixed default.

from urllib.parse import urlsplit

ALLOWED_PATHS = ("/dashboard", "/courses/", "/settings")

def safe_redirect(target: str) -> str:
    parts = urlsplit(target)
    if parts.scheme or parts.netloc or not target.startswith("/") or target.startswith("//") or "\\" in target:
        return "/dashboard"
    if not any(target == p or target.startswith(p) for p in ALLOWED_PATHS):
        return "/dashboard"
    return target

for target in ["/courses/sec-101", "https://example.net/login", "//example.net", "/\\example.net", "/admin"]:
    print(f"{target!r:<28} -> {safe_redirect(target)}")
'/courses/sec-101'           -> /courses/sec-101
'https://example.net/login'  -> /dashboard
'//example.net'              -> /dashboard
'/\\example.net'             -> /dashboard
'/admin'                     -> /dashboard

9.8 Browser storage

Avoid storing long-lived bearer tokens in JavaScript-accessible storage when the threat model makes XSS a concern. Understand the trade-offs between secure cookies, in-memory tokens, refresh-token rotation, and browser architecture. Never store passwords in local storage.

9.9 Content types and downloads

Set correct content types; use safe Content-Disposition behavior for downloads; avoid rendering uploaded active content from a trusted application origin; and authorize file access on every request.

Practice

Create a web deployment checklist covering TLS, cookies, CORS, CSP, cache controls, redirects, error pages, file downloads, and logout/session revocation.

Quiz

? A session cookie has `HttpOnly`. What does that achieve?
+ Page JavaScript cannot read it through `document.cookie`. :: It reduces token theft through XSS.
- It prevents XSS. :: Injected script can still act within the page.
- It is only sent over HTTPS. :: That is `Secure`.
- It prevents CSRF. :: That is closer to `SameSite` and anti-CSRF tokens.

? Which CORS configuration is a mistake?
- Listing two exact trusted origins :: That is the recommended approach.
+ Reflecting whatever `Origin` the request sends, with credentials allowed :: Any site could then read authenticated responses.
- Not sending CORS headers for an API only used same-origin :: No cross-origin reads are needed.
- Allowing `GET` from a trusted origin without credentials :: Reasonable for public data.

? Which items should not be placed in URLs? (select all that apply)
+ Password-reset tokens :: URLs end up in logs, history and referrer headers.
+ Session identifiers :: Same reason.
+ API keys :: Same reason.
- A public course slug :: Non-secret identifiers are fine in URLs.