Objective. Students identify SQL injection, XSS, cross-site request forgery (CSRF), and insecure direct object reference vulnerabilities in provided code samples and apply the corresponding remediation technique in both PHP and Python
This lesson, its worked examples and its practice questions has not yet been verified by an industry-certified professional or by a certification or approval body. It is a study draft and may contain errors. Do not use it as instructions for work on a job site or on live equipment. Always follow your instructor, your supervising professional, and current official references and regulations.
VoTechWorks program approval and accreditation are still in progress. Credentials are issued only by the certifying bodies named in each program, after their own exams.
Every web application you build is a potential target. Attackers probe sites continuously, looking for predictable mistakes in how code handles user input, manages sessions, or controls access to data. Four vulnerabilities appear so consistently across real-world breaches that the Open Web Application Security Project (OWASP) has tracked them in its Top Ten list for years: SQL injection, cross-site scripting (XSS), cross-site request forgery (CSRF), and insecure direct object reference (IDOR). Learning to recognize these flaws and apply the correct fix is a core professional skill — and a legal responsibility when you handle other people's data.
SQL injection happens when user-supplied input is concatenated directly into a database query without sanitization. An attacker types SQL syntax into a form field, and the database executes it as a command rather than treating it as data.
Vulnerable PHP example:
```php
$query = "SELECT * FROM users WHERE username = '" . $_POST['username'] . "'";
```
If the user types `' OR '1'='1`, the query returns every row in the table.
Remediation — Prepared Statements with Parameterized Queries:
```php
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$_POST['username']]);
```
The database driver separates code from data; no input can change the query structure.
Python (with sqlite3 or a library such as psycopg2):
```python
cursor.execute("SELECT * FROM users WHERE username = %s", (username,))
```
Always use the placeholder syntax provided by the database driver — never format strings into queries.
XSS occurs when an application echoes user input back to the browser without encoding it. The browser interprets the input as HTML or JavaScript and executes it. An attacker can steal session cookies, redirect users, or deface a page.
Vulnerable PHP:
```php
echo "Hello, " . $_GET['name'];
```
Input of `<script>alert(document.cookie)</script>` runs in every visitor's browser.
Remediation — Output Encoding:
```php
echo "Hello, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
```
`htmlspecialchars()` converts `<`, `>`, `"`, and `'` to safe HTML entities.
Python (Jinja2 templating, used in Flask): Auto-escaping is enabled by default in Jinja2 when you render `.html` templates. Never mark user data `safe` unless you have specifically sanitized it. If building strings manually, use Python's `html.escape()` function.
CSRF tricks a logged-in user's browser into sending an unwanted request to your application. Because the browser automatically includes cookies, the server cannot tell the request is forged. A common attack embeds an invisible form or image tag on a malicious page that submits a state-changing action (like changing a password or placing an order) to your site.
Remediation — Synchronizer Token Pattern:
1. When the form loads, generate a random, unpredictable token and store it in the user's session.
2. Embed the token as a hidden field in the form.
3. On submission, compare the posted token to the session token. Reject the request if they do not match.
An attacker on a different origin cannot read the victim's session token, so the forged request will fail the check.
PHP example (token generation and validation):
```php
// Generate token and store in session
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// In the form
echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';
// On form submission
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
die('CSRF validation failed.');
}
```
Use `hash_equals()` rather than `==` to prevent timing attacks.
Python / Flask: The Flask-WTF extension provides CSRF protection automatically via its `CSRFProtect` class and `{{ form.hidden_tag() }}` template tag.
IDOR occurs when an application exposes an internal identifier — such as a database record ID — directly in a URL or form parameter, and does not verify that the requesting user is authorized to access that record.
Example: `https://example.com/invoice?id=1042` — if the application fetches the invoice matching `id` without checking ownership, changing `1042` to `1041` may display another customer's invoice.
Remediation:
PHP:
```php
$stmt = $pdo->prepare("SELECT * FROM invoices WHERE id = ? AND user_id = ?");
$stmt->execute([$_GET['id'], $_SESSION['user_id']]);
```
Python:
```python
cursor.execute("SELECT * FROM invoices WHERE id = %s AND user_id = %s",
(invoice_id, session['user_id']))
```
Handling other people's personal data carries legal obligations under statutes such as state breach-notification laws and, where applicable, federal sector-specific rules (health, financial). Even in a vocational training environment:
Defensive coding is not optional polish; it is the standard of care expected of every professional web developer.
Answer each question, then check it. Nothing is recorded; this is your own practice.
A free tech program — complimentary, as our commitment to get America working. Help us build VoTechWorks. Tell us what works, what doesn’t, and what you want to learn.