Skip to content
· 10 min read INFO @Sdmrf

How Web Applications Work (Before You Break Them)

Client-server architecture, request flow, cookies, sessions, and APIs. You need to understand the machine before you can find the cracks.

On this page

In the networking module, we covered what happens when you visit a website - DNS, TCP, TLS, HTTP. That was the transport layer. Now we go higher: how the application itself works.

Before you can find vulnerabilities in web apps, you need to understand what they’re made of. Every web security bug - XSS, SQL injection, authentication bypass - exists because of how these pieces interact. Learn the pieces first.

The Client-Server Model

Every web application has two halves:

The Client (Frontend):

  • Your browser
  • Runs HTML, CSS, and JavaScript
  • Handles what you see and interact with
  • Runs on your machine

The Server (Backend):

  • A computer somewhere in a data center
  • Runs application code (Python, PHP, Node.js, Java, etc.)
  • Talks to databases
  • Handles business logic, authentication, data processing
  • Runs on their machine

The client asks for things. The server decides what to give back. They communicate over HTTP.

Browser (Client) ──HTTP Request──▶ Server (Backend)
                 ◀──HTTP Response──

Why This Split Matters for Security

Anything on the client can be manipulated. The user controls their browser. They can modify HTML, change JavaScript, alter requests before they’re sent, and forge data.

The server must never trust the client. Every security rule, every permission check, every validation must happen on the server side. Client-side checks are for user experience, not security.

This single principle - never trust client-side input - underlies almost every web vulnerability.

The Request-Response Cycle

Let’s trace what happens when you submit a login form.

1. The Form (Client Side)

<form action="/login" method="POST">
  <input type="text" name="username" />
  <input type="password" name="password" />
  <button type="submit">Login</button>
</form>

You type your credentials and click Login.

2. The HTTP Request

Your browser constructs and sends:

POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=alice&password=secret123

Your credentials travel over the network. With HTTPS, they’re encrypted. Without it, they’re plaintext - readable by anyone between you and the server.

3. Server Processing

The server receives the request and:

  1. Extracts username and password from the request body
  2. Looks up alice in the database
  3. Compares the password against the stored hash
  4. If valid: creates a session and sends back a cookie
  5. If invalid: returns an error

4. The HTTP Response

HTTP/1.1 302 Found
Set-Cookie: session=abc123def456; HttpOnly; Secure; Path=/
Location: /dashboard

The server sets a cookie (we’ll cover these next) and redirects you to the dashboard.

5. Subsequent Requests

Every request after login includes the cookie:

GET /dashboard HTTP/1.1
Host: example.com
Cookie: session=abc123def456

The server reads the cookie, looks up the session, knows it’s Alice, and returns her dashboard.

Cookies: How the Server Remembers You

HTTP is stateless - each request is independent. The server doesn’t inherently know that request #2 came from the same person as request #1.

Cookies solve this. They’re small pieces of data the server asks your browser to store and send back with every request.

How Cookies Work

1. Server → Browser: "Store this: session=abc123"  (Set-Cookie header)
2. Browser → Server: "Here's what you gave me: session=abc123"  (Cookie header)
3. Server: "abc123 maps to Alice. Show her dashboard."
AttributePurpose
HttpOnlyJavaScript can’t read the cookie. Defends against XSS cookie theft
SecureOnly sent over HTTPS. Prevents interception on unencrypted connections
SameSiteControls cross-site sending. Defends against CSRF attacks
PathCookie only sent for requests to this path
DomainCookie sent to this domain and subdomains
Expires/Max-AgeWhen the cookie expires

Why Cookies Matter for Security

Cookies are how most web apps handle authentication. If you steal someone’s session cookie, you become them. No password needed. This is called session hijacking.

Ways cookies get stolen:

  • XSS: Malicious JavaScript reads document.cookie and sends it to the attacker
  • Network sniffing: Cookie sent over HTTP (not HTTPS) is visible in traffic
  • CSRF: Tricking a user’s browser into making requests with their cookie attached

The HttpOnly and Secure flags exist specifically to prevent the first two scenarios.

Sessions vs Tokens

There are two common approaches to tracking logged-in users.

Server-Side Sessions

The traditional approach:

  1. User logs in
  2. Server creates a session (data stored on the server) with a random ID
  3. Server sends the session ID as a cookie
  4. Browser sends the ID with every request
  5. Server looks up the session data by ID
Cookie: session=abc123

        └── Server looks up: abc123 → {user: "alice", role: "admin", loginTime: ...}

The session data lives on the server. The cookie is just a reference key.

Tokens (JWT)

The modern approach, especially for APIs:

  1. User logs in
  2. Server creates a token containing user data, signed cryptographically
  3. Server sends the token
  4. Browser stores it and sends it with every request (usually in a header)
  5. Server verifies the signature - no lookup needed
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWxpY2UiLCJyb2xlIjoiYWRtaW4ifQ.signature

A JWT has three parts (separated by dots):

  • Header: Algorithm info
  • Payload: User data (claims)
  • Signature: Proves the token wasn’t tampered with

The data is in the token itself. The server doesn’t need to store anything.

Security Implications

ConcernSessionsTokens (JWT)
RevocationEasy - delete the session on the serverHard - token is valid until it expires
Data exposureData stays on serverPayload is Base64-encoded (readable, not encrypted)
StorageServer needs memory/databaseStateless - no server storage
ScalabilityHarder (shared session store needed)Easier (any server can verify)

Common JWT mistakes:

  • Setting algorithm to none (no signature verification)
  • Using weak signing keys (crackable with brute force)
  • Not validating expiration
  • Storing sensitive data in the payload (it’s only Base64, not encrypted)

APIs: How Modern Apps Communicate

Modern web apps often separate the frontend from the backend entirely. The frontend (React, Vue, Angular) runs in the browser and communicates with the backend through APIs (Application Programming Interfaces).

REST APIs

Most web APIs use REST (Representational State Transfer). Same HTTP methods you already know:

GET    /api/users/123       → Get user 123
POST   /api/users           → Create a new user
PUT    /api/users/123       → Update user 123
DELETE /api/users/123       → Delete user 123

Responses are usually JSON:

{
  "id": 123,
  "name": "Alice",
  "email": "alice@example.com",
  "role": "admin"
}

Why APIs Matter for Security

APIs are just HTTP endpoints without the browser UI. Every security issue that applies to web forms applies to APIs - plus some extras:

  • Broken access control: Can user A access user B’s data by changing the ID in the URL? (/api/users/124 instead of /api/users/123)
  • Missing authentication: Are there API endpoints that don’t require login?
  • Excessive data exposure: Does the API return more data than the frontend shows? (password hashes, internal IDs, other users’ data)
  • Rate limiting: Can you make unlimited login attempts through the API?

Testing APIs directly (with curl or tools like Burp Suite) often reveals vulnerabilities the frontend UI hides.

The Database Layer

Behind most web applications sits a database that stores everything: users, content, settings, transactions.

How the App Talks to the Database

Browser → Server (application code) → Database

The application builds database queries based on user input:

# The app receives username from the login form
username = request.form['username']

# It builds a SQL query
query = f"SELECT * FROM users WHERE username = '{username}'"

# It sends the query to the database
result = database.execute(query)

This specific pattern - building queries from user input - is where SQL injection lives. We’ll cover that in detail in a dedicated post.

Common Databases

DatabaseTypeUsed For
MySQL / MariaDBRelational (SQL)Most PHP web apps, WordPress
PostgreSQLRelational (SQL)Modern web apps, data-heavy applications
SQLiteRelational (SQL)Small apps, mobile apps, embedded
MongoDBDocument (NoSQL)JavaScript/Node.js apps
RedisKey-ValueCaching, sessions

Input and Output: Where Vulnerabilities Live

Almost every web vulnerability comes from one problem: untrusted input being used without proper handling.

The Pattern

User Input → Application Processing → Output

If the application doesn’t properly validate/sanitize input at step 2, or doesn’t properly encode output at step 3, vulnerabilities happen:

Input Goes ToWithout HandlingVulnerability
HTML pageUser input rendered as HTMLXSS
SQL queryUser input treated as SQL codeSQL Injection
OS commandUser input executed as a commandCommand Injection
File pathUser input used to access filesPath Traversal
URL redirectUser input controls redirect destinationOpen Redirect

The defense is always the same principle: treat all user input as potentially malicious. Validate, sanitize, and encode it appropriately for where it’s going.

Developer Tools: Your X-Ray Vision

Your browser has built-in tools that let you see everything happening under the hood. This is how security testers examine web apps.

How to Open Dev Tools

Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac) in any browser.

Key Tabs

TabWhat You SeeSecurity Use
ElementsLive HTML/CSSInspect forms, hidden fields, client-side checks
ConsoleJavaScript executionRun JS, test for XSS, read errors
NetworkAll HTTP requests/responsesSee API calls, cookies, headers, parameters
ApplicationCookies, storage, tokensInspect/modify cookies and local storage
SourcesJavaScript source codeFind client-side logic, API keys, secrets

What to Look For

Network tab:
├── API endpoints the frontend calls (often undocumented)
├── Parameters sent with each request
├── Cookies being set and their attributes
├── Response data (sometimes more than the UI shows)
└── Authentication headers (tokens, API keys)

Application tab:
├── Session cookies (are they HttpOnly? Secure?)
├── Local Storage (JWTs stored here are vulnerable to XSS)
└── Session Storage

Try It Yourself

Pick any website you use (your own or a public one) and explore with dev tools:

1. Open dev tools (F12)
2. Go to the Network tab
3. Log in to the site
4. Watch the login request - what data is sent? What comes back?
5. Click around - see the API calls being made
6. Go to Application tab - look at the cookies
7. Check: do cookies have HttpOnly and Secure flags?

For hands-on practice with intentionally vulnerable apps:

  • OWASP Juice Shop - Modern vulnerable web app, beginner-friendly
  • DVWA (Damn Vulnerable Web Application) - Classic training app
  • PortSwigger Web Security Academy - Free labs with guided learning

What’s Next

Now you know how web apps are built: client-server communication, cookies, sessions, tokens, APIs, and databases. You understand the trust model and where input flows.

Time to break things. In the next post, we’ll cover Cross-Site Scripting (XSS) - the most common web vulnerability and your introduction to how untrusted input becomes a security problem.

References


Every web vulnerability is a failure to enforce a boundary - between user input and code, between user A and user B, between client and server. Understand the boundaries, and you’ll understand the bugs.

Related Articles