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
Ground Up: How Things Break
Part 1 of 4
View all parts
- 1How Web Applications Work (Before You Break Them)
- 2Your First Vulnerability: Understanding XSS
- 3SQL Injection Explained: Talking to Databases You Shouldn't
- 4Authentication Attacks: Passwords, Sessions, and Tokens
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:
- Extracts
usernameandpasswordfrom the request body - Looks up
alicein the database - Compares the password against the stored hash
- If valid: creates a session and sends back a cookie
- 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."
Cookie Attributes
| Attribute | Purpose |
|---|---|
HttpOnly | JavaScript can’t read the cookie. Defends against XSS cookie theft |
Secure | Only sent over HTTPS. Prevents interception on unencrypted connections |
SameSite | Controls cross-site sending. Defends against CSRF attacks |
Path | Cookie only sent for requests to this path |
Domain | Cookie sent to this domain and subdomains |
Expires/Max-Age | When 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.cookieand 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:
- User logs in
- Server creates a session (data stored on the server) with a random ID
- Server sends the session ID as a cookie
- Browser sends the ID with every request
- 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:
- User logs in
- Server creates a token containing user data, signed cryptographically
- Server sends the token
- Browser stores it and sends it with every request (usually in a header)
- 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
| Concern | Sessions | Tokens (JWT) |
|---|---|---|
| Revocation | Easy - delete the session on the server | Hard - token is valid until it expires |
| Data exposure | Data stays on server | Payload is Base64-encoded (readable, not encrypted) |
| Storage | Server needs memory/database | Stateless - no server storage |
| Scalability | Harder (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/124instead 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
| Database | Type | Used For |
|---|---|---|
| MySQL / MariaDB | Relational (SQL) | Most PHP web apps, WordPress |
| PostgreSQL | Relational (SQL) | Modern web apps, data-heavy applications |
| SQLite | Relational (SQL) | Small apps, mobile apps, embedded |
| MongoDB | Document (NoSQL) | JavaScript/Node.js apps |
| Redis | Key-Value | Caching, 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 To | Without Handling | Vulnerability |
|---|---|---|
| HTML page | User input rendered as HTML | XSS |
| SQL query | User input treated as SQL code | SQL Injection |
| OS command | User input executed as a command | Command Injection |
| File path | User input used to access files | Path Traversal |
| URL redirect | User input controls redirect destination | Open 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
| Tab | What You See | Security Use |
|---|---|---|
| Elements | Live HTML/CSS | Inspect forms, hidden fields, client-side checks |
| Console | JavaScript execution | Run JS, test for XSS, read errors |
| Network | All HTTP requests/responses | See API calls, cookies, headers, parameters |
| Application | Cookies, storage, tokens | Inspect/modify cookies and local storage |
| Sources | JavaScript source code | Find 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
- MDN - HTTP Cookies
- OWASP - Top 10 Web Application Security Risks
- PortSwigger Web Security Academy
- JWT.io - Decode and inspect JWTs
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
Authentication Attacks: Passwords, Sessions, and Tokens
How login systems break - brute force, credential stuffing, session hijacking, token flaws, and MFA bypass. The complete beginner's guide to auth attacks.
SQL Injection Explained: Talking to Databases You Shouldn't
How SQL injection works, why it's devastating, and how to prevent it. From basic injection to blind SQLi, explained for beginners.
Your First Vulnerability: Understanding XSS
Cross-Site Scripting explained from scratch - what it is, the three types, how attackers exploit it, and how to prevent it. With safe practice labs.