Files
Computer-Fundamentals/js/04-networking-storage-security.md
tarun-elango be31df2d44 more text
2026-04-26 14:09:04 -04:00

17 KiB

04. Networking, Storage, and Security

At this point in the handbook, you know how JavaScript runs and how browsers render. The next question is: how does a browser app talk to the outside world, keep data around, and stay safe while doing it?

This chapter covers that boundary.

Networking, storage, and security are deeply connected in browsers. A request is not just "send bytes to a server." It is constrained by origin policy, cookies, credential rules, caching, and user safety. Storage is not just "save some data." It is tied to persistence, quota, privacy, and attack surface. Authentication is not just a backend concern because the browser decides which credentials are attached automatically and which APIs are exposed to JavaScript.

This file connects directly to:

HTTP and HTTPS From the Browser's Point of View

Backend engineers often describe HTTP in server-centric terms: routes, handlers, payloads, proxies. Frontend engineers need a browser-centric model too.

From a browser page's perspective, HTTP is how it gets almost everything:

  • the initial HTML document
  • JavaScript bundles or modules
  • CSS files
  • images, fonts, and media
  • API data for in-page updates

So HTTP is not a side system. It is the bloodstream of the web page.

What the Browser Actually Cares About

When the browser makes or receives an HTTP request, it is not only tracking the URL and body. It also cares about:

  • origin and security policy
  • request method and headers
  • cacheability
  • cookies and credentials
  • redirect behavior
  • content type and decoding
  • connection reuse and protocol version
  • whether the response is allowed to reach page JavaScript

That last point matters. A server can return bytes, but the browser still decides whether page code is allowed to see them under the web security model.

Why HTTPS Matters So Much in Browsers

HTTPS is HTTP over TLS. The practical browser reason is not just privacy in the abstract. It is trust and integrity.

Without HTTPS, an attacker on the network path could:

  • read traffic
  • modify scripts in transit
  • inject hostile content
  • steal cookies without proper protection

If an attacker can alter your JavaScript bundle in transit, they effectively own your page. That is why secure transport is foundational to browser security rather than a nice extra.

Modern browser features also increasingly assume secure contexts. Many APIs either require or strongly prefer HTTPS because the browser only wants to expose powerful capabilities in a transport it can trust more.

Request Types the Browser Makes

From the browser's perspective, not all requests are the same.

Navigation Requests

These load a new document. Typing a URL in the address bar or clicking a normal link usually triggers navigation.

Subresource Requests

These fetch supporting assets for a page:

  • scripts
  • stylesheets
  • images
  • fonts

Programmatic Requests

These are created by JavaScript using APIs such as fetch or XMLHttpRequest. They are central to single-page apps because they let the UI update without a full-page reload.

This distinction matters because browsers handle navigation, rendering, and security policies differently across these request categories.

The Fetch Lifecycle

fetch looks simple in code, but a lot happens between await fetch(...) and your response handler.

const response = await fetch("/api/products", {
  method: "GET",
  credentials: "include"
});

const data = await response.json();

High-Level Fetch Request Lifecycle

flowchart LR
    A[JavaScript calls fetch] --> B[Browser validates request options]
    B --> C[Check service worker and caches]
    C --> D[Apply origin and CORS rules]
    D --> E[Reuse or create network connection]
    E --> F[Send HTTP request]
    F --> G[Receive response headers and body]
    G --> H[Resolve fetch promise with Response object]
    H --> I[JavaScript consumes body stream or parsed data]

Step-by-Step Intuition

  1. JavaScript creates a request description.
  2. The browser checks request mode, credentials settings, headers, and policy restrictions.
  3. A service worker may intercept the request if one is active.
  4. The browser may consult caches before going to the network.
  5. Security rules such as same-origin policy and CORS are applied.
  6. The browser uses an existing connection or establishes a new one.
  7. Response headers arrive, then body data streams in.
  8. The fetch promise resolves once the response object is available.
  9. Later body-reading methods such as response.json() perform additional async work.

Important Subtlety: fetch Resolves on HTTP Errors Too

fetch rejects on network-level failure, abort, or some policy failures. But a normal HTTP error such as 404 or 500 still produces a response object.

That is why this is common:

const response = await fetch("/api/user");

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

This behavior makes sense once you realize that HTTP error status is still a valid HTTP response, not a transport failure.

Streams and Why the Browser Works This Way

Response bodies are often stream-oriented because browsers do not want to wait for the entire payload to be fully buffered before exposing data. Streaming improves memory efficiency and latency for large responses.

This becomes especially important for:

  • large downloads
  • video and media delivery
  • streaming server responses
  • progressively rendered HTML or data pipelines

Same-Origin Policy: The Browser's Core Isolation Rule

The same-origin policy is one of the web's foundational security rules.

At a useful level, an origin is a combination of:

  • scheme, such as http or https
  • host, such as app.example.com
  • port, such as 443

If two resources differ in one of those, they are different origins.

Why This Policy Exists

Imagine you are logged into your bank in one browser tab and visit a malicious site in another. Without origin isolation, that malicious page could simply read sensitive data from the bank site using your browser's authenticated session.

The same-origin policy exists to prevent one origin's page JavaScript from freely reading data from another origin.

This is one of the most important "why it works this way" topics in browser engineering. The browser is not trying to make developers suffer. It is acting as a guard between mutually untrusting websites loaded by the same user.

CORS: Controlled Relaxation of Same-Origin Restrictions

CORS, or Cross-Origin Resource Sharing, is a browser mechanism that lets servers explicitly say which cross-origin requests are allowed.

Deep Intuition

Same-origin policy says: "pages cannot freely read responses from other origins."

CORS adds: "unless the target server explicitly opts in under defined rules."

What CORS Is and Is Not

  • CORS is enforced by browsers.
  • CORS is mainly about whether frontend JavaScript can access the response.
  • CORS does not stop server-to-server requests because there is no browser enforcing the rule there.
  • CORS is not an authentication mechanism.

Simple Request vs Preflighted Request

Some cross-origin requests can be sent directly, and the browser checks whether the response includes the right CORS headers.

Other requests require a preflight: an OPTIONS request sent first to ask the server what is allowed.

Triggers for preflight commonly include:

  • non-simple methods such as PUT or DELETE
  • certain custom headers
  • certain content types outside the simple set

CORS Flow

sequenceDiagram
    participant App as Browser App
    participant Browser as Browser Security Layer
    participant API as API Server

    App->>Browser: fetch cross-origin resource
    alt preflight required
        Browser->>API: OPTIONS preflight
        API-->>Browser: Access-Control-* headers
    end
    Browser->>API: actual request
    API-->>Browser: response with CORS headers
    Browser-->>App: expose response only if policy allows

Credentials and CORS

Cross-origin requests become trickier when cookies or other credentials are involved.

If credentials are included:

  • the browser requires tighter CORS rules
  • wildcard origin settings usually cannot be used in the same permissive way
  • server intent must be explicit

This is deliberate. If authenticated browser requests could be casually shared across origins, cross-site data leaks would be much easier.

Cookies, localStorage, sessionStorage, and IndexedDB

Browser storage is not one thing. Different storage mechanisms exist because the web needs different tradeoffs.

Storage Comparison

Storage Lifetime Sent automatically with requests Typical size Best use
Cookies configurable expiry or session Yes, depending on scope and rules small session/auth and server-visible state
localStorage persists until cleared No small-ish simple client-only persistence
sessionStorage per-tab session No small-ish temporary tab-scoped data
IndexedDB persistent No much larger structured app data and offline caching

Cookies

Cookies are small key-value pieces of data associated with requests to matching origins and paths.

Why cookies are special:

  • the browser can attach them automatically to matching requests
  • servers can set them using Set-Cookie
  • security attributes such as HttpOnly, Secure, and SameSite affect how they behave

That automatic attachment makes cookies powerful for authentication, but also sensitive from a security standpoint.

localStorage

localStorage is a simple synchronous key-value API accessible from JavaScript.

Why it is popular:

  • easy to use
  • persistent across page reloads
  • fine for small client-only preferences

Why it should not be overused:

  • synchronous API can block if abused
  • string-only interface is primitive
  • available to JavaScript, so any successful XSS can read it

sessionStorage

sessionStorage is similar to localStorage but scoped to the lifetime of a tab or page session.

Useful for:

  • temporary wizard progress
  • transient UI state that should not survive a full long-term session

IndexedDB

IndexedDB is the browser's serious client-side database option.

It exists because richer apps need more than tiny string storage:

  • offline data
  • larger structured records
  • indexes and queries
  • versioned schema upgrades

If localStorage is a sticky note, IndexedDB is a filing cabinet.

Storage Landscape Diagram

flowchart TD
    A[Browser App] --> B[Cookies]
    A --> C[localStorage]
    A --> D[sessionStorage]
    A --> E[IndexedDB]
    B --> F[Automatically attached to matching HTTP requests]
    C --> G[Client-side key value persistence]
    D --> H[Tab-scoped temporary persistence]
    E --> I[Structured offline-capable app data]

Authentication in Browser Apps

Frontend interview questions about auth are often really questions about browser behavior.

In a traditional server-backed web app:

  1. user logs in
  2. server verifies credentials
  3. server sends a session cookie
  4. browser stores it
  5. browser automatically includes it on future matching requests
  6. server uses it to find the session state
sequenceDiagram
    participant User as User Browser
    participant App as Frontend App
    participant API as Server

    App->>API: POST /login with credentials
    API-->>User: Set-Cookie session=abc
    User->>User: Browser stores cookie
    App->>API: GET /profile
    User->>API: Cookie: session=abc
    API-->>App: profile data

Why this model is strong:

  • browser handles cookie attachment automatically
  • server can invalidate session centrally
  • HttpOnly cookies are not readable by JavaScript, reducing exposure to token theft via XSS

JWT Basics

JWTs, or JSON Web Tokens, are a token format often used in stateless auth systems. The token itself can carry claims and can be verified by the server.

Important nuance: JWT is a token format, not a storage strategy.

You still need to decide where to keep it:

  • in memory
  • in a cookie
  • in storage accessible to JavaScript

That decision affects security properties more than the string format does.

If you store auth material in localStorage, JavaScript can read it, which means XSS can read it too.

If you store auth material in HttpOnly cookies, JavaScript cannot read it directly, which is often safer against token exfiltration. But cookies are automatically attached to requests, so CSRF protections become especially important.

This is why authentication discussions in browser apps are always tied to both XSS and CSRF.

XSS: Cross-Site Scripting

XSS happens when untrusted content is executed as script in your page's origin.

Why It Is So Dangerous

The browser treats injected script as if it were your app's own JavaScript running in your origin. That means it can:

  • read page data
  • make authenticated requests
  • manipulate the UI
  • access storage available to JavaScript
  • potentially exfiltrate secrets

Once XSS lands, many other defenses become weaker because the attacker is now "inside" your app's trust boundary.

Common Causes

  • injecting unsanitized HTML
  • unsafe template interpolation
  • dangerous use of innerHTML
  • third-party script compromise

Defenses

  • escape or sanitize untrusted content
  • prefer safe DOM APIs and framework escaping defaults
  • limit inline script execution with CSP
  • reduce token exposure to JavaScript when possible

CSRF: Cross-Site Request Forgery

CSRF exploits the fact that the browser may automatically attach cookies to requests.

An attacker cannot necessarily read your app's responses because of same-origin policy, but they may still be able to cause the browser to send authenticated requests if the app relies on automatically attached credentials.

Why CSRF Exists

The browser is trying to be convenient. If the user is logged in, the browser sends matching cookies automatically. That convenience is exactly what attackers try to abuse.

Defenses

  • SameSite cookie settings
  • anti-CSRF tokens
  • checking origin or referer where appropriate
  • using auth patterns that do not blindly trust automatic cross-site requests

CSP: Content Security Policy

CSP is a browser-enforced policy that lets a site restrict what content and scripts are allowed to execute.

Think of CSP as a damage-limiting policy layer. It does not replace safe coding, but it can greatly reduce what injected content is able to do.

Examples of what CSP can control:

  • which script sources are allowed
  • whether inline scripts are allowed
  • which image, style, and connect destinations are allowed

This matters in real apps because modern frontends often load many third-party resources. CSP helps turn "trust everything the page references" into an explicit policy.

Browser Security Is a System, Not a Single Feature

Strong browser security comes from layers working together:

  • HTTPS protects transport integrity and confidentiality
  • same-origin policy isolates sites from one another
  • CORS selectively relaxes read restrictions under server control
  • cookie attributes constrain credential behavior
  • XSS defenses stop hostile code from entering your origin
  • CSRF defenses protect automatically attached credentials
  • CSP reduces the blast radius of injection mistakes

This layered thinking is what interviewers want when they ask security questions. They are usually testing whether you understand that the browser is an active security participant, not a passive request sender.

Interview-Ready Summary

  • The browser cares about origin, credentials, cache, and security policy in addition to raw HTTP semantics.
  • fetch triggers browser-managed request logic involving policy checks, caching, networking, and async response delivery.
  • Same-origin policy prevents one origin's page JavaScript from freely reading another origin's data.
  • CORS is a browser-enforced mechanism that allows controlled cross-origin access when the server opts in.
  • Cookies are automatically attached to matching requests; localStorage, sessionStorage, and IndexedDB are not.
  • HttpOnly cookies reduce JavaScript access to sensitive auth material, while JavaScript-readable storage is more exposed to XSS.
  • XSS, CSRF, and CSP are related browser security topics, not isolated trivia items.

Continue with 05-real-world-architecture-patterns.md. That chapter turns all of these browser primitives into application design choices: SPA vs MPA, SSR vs hydration, state management, caching, and production frontend architecture.