Scripting LanguageUnit 1111 min read
Web Form Validation & Security: Rules, Attacks & Defenses
Unit 11 of Scripting Language covers client-side (JavaScript) and server-side (PHP) form validation techniques, common security threats (SQLi, XSS, CSRF), and defensive coding practices. Learn to validate inputs, sanitize data, and secure forms against attacks with real-world examples from eSewa, Daraz, and Ncell.
TAKEAWAYS:
- Validation vs. Sanitization: Client-side validation improves UX but never trust it; server-side validation is mandatory.
- Common Attacks: SQL injection, XSS, and CSRF exploit poorly validated inputs—always escape user data.
- PHP Filters: Use
filter_var()andfilter_input()to validate emails, numbers, and URLs before processing. - JavaScript Events:
onblur,onsubmit, andonchangetrigger validation dynamically for instant feedback. - Security Headers:
Content-Security-PolicyandX-XSS-Protectionheaders mitigate XSS attacks. - Real-World Impact: A single SQLi vulnerability in a bank’s login form could expose all customer data (e.g., Nepal Rastra Bank’s past breaches).
1. Why Validate Forms?
Forms are the primary attack surface of web apps. Without validation:
- Malicious data (e.g.,
<script>alert('hacked')</script>) can break your app. - Invalid inputs (e.g., negative age, SQL keywords) crash databases or logic.
- User experience suffers (e.g., Daraz rejecting orders due to invalid phone formats).
2. Types of Validation
A. Client-Side Validation (JavaScript)
Purpose: Improve user experience by catching errors before submission. Limitations: Can be bypassed (disabled JavaScript, tampered requests).
Common JavaScript Validation Methods:
flowchart TD
A["User Input"] --> B["onblur Event"]
B --> C["Check Length\nRegex\nType"]
C -->|"Valid"| D["Enable Submit"]
C -->|"Invalid"| E["Show Error\nRed Border"]
D --> F["Form Submission"]Example: Email Validation
function validateEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
document.getElementById("email").addEventListener("blur", function() {
if (!validateEmail(this.value)) {
this.style.border = "2px solid red";
alert("Invalid email!");
}
});
TRACE:
| Step | email Value |
re.test() |
Action |
|---|---|---|---|
| 1 | user@example.com |
true |
Border: green (valid) |
| 2 | user@.com |
false |
Border: red, alert shown |
Real-World Use:
- eSewa’s login form uses client-side validation to reject invalid phone numbers (e.g.,
+97798XXXXXX) instantly, reducing server load.
B. Server-Side Validation (PHP)
Purpose: Mandatory security layer. Even if client-side passes, server must re-validate.
PHP’s filter_var() for Common Checks:
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$phone = filter_input(INPUT_POST, 'phone', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^98\d{8}$/']]);
if (!$email || !$phone) {
die("Invalid input!");
}
TRACE:
Input ($_POST) |
filter_var() Result |
Validation Pass? |
|---|---|---|
email=test@ |
false |
❌ Fail |
phone=981234567 |
981234567 |
✅ Pass |
Real-World Use:
- Khalti’s payment form validates card numbers using
FILTER_VALIDATE_CREDIT_CARDto block fraudulent transactions.
3. Common Security Threats & Fixes
A. SQL Injection (SQLi)
Attack: Malicious SQL queries via form inputs. Example: A login form with:
$query = "SELECT * FROM users WHERE username = '$_POST[username]' AND password = '$_POST[password]'";
Exploit: User enters admin' -- → Bypasses password check!
Fix: Prepared Statements (PDO)
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute(['username' => $_POST['username']]);
Visual:
flowchart LR
A["User Input:\nadmin' --"] --> B["Unsafe Query\nSQLi"]
A --> C["Safe Query\nPDO"] --> D["No SQLi"]Real-World Impact:
- Nepal’s Ncell faced SQLi attacks in 2020 due to unvalidated API inputs, exposing customer data.
B. Cross-Site Scripting (XSS)
Attack: Injecting malicious scripts into web pages.
Example: A comment field storing <script>stealCookies()</script>.
Fix: Escape output with htmlspecialchars():
echo htmlspecialchars($_POST['comment'], ENT_QUOTES, 'UTF-8');
Visual:
sequenceDiagram
User->>Server: <script>alert('XSS')</script>
Server->>Server: htmlspecialchars()
Server-->>Browser: <script>alert('XSS')</script>Real-World Use:
- YouTube escapes all user-uploaded comments to prevent XSS.
C. Cross-Site Request Forgery (CSRF)
Attack: Tricking users into submitting unwanted requests (e.g., changing passwords). Fix: Use CSRF tokens in forms:
session_start();
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// In form:
echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';
// On submission:
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die("CSRF attack blocked!");
}
Real-World Use:
- Facebook uses CSRF tokens to prevent unauthorized actions (e.g., liking posts via malicious links).
4. Form Validation Worked Example: BCA Registration
Requirements:
- Name: 3–40 chars, letters/spaces only.
- Email: Valid format.
- Phone: 10-digit Nepali number (starts with 98).
- Password: 8+ chars, at least 1 number.
HTML + JavaScript (Client-Side):
<form id="bcaForm">
<input type="text" id="name" placeholder="Name" required>
<input type="email" id="email" placeholder="Email" required>
<input type="tel" id="phone" placeholder="Phone" required>
<input type="password" id="password" placeholder="Password" required>
<button type="submit">Register</button>
</form>
<script>
document.getElementById("bcaForm").addEventListener("submit", function(e) {
const name = document.getElementById("name").value;
const phone = document.getElementById("phone").value;
if (!/^[A-Za-z\s]{3,40}$/.test(name)) {
alert("Name must be 3-40 letters only!");
e.preventDefault();
}
if (!/^98\d{8}$/.test(phone)) {
alert("Phone must be 10-digit Nepali number!");
e.preventDefault();
}
});
</script>
PHP (Server-Side):
$errors = [];
// Name validation
if (!preg_match("/^[A-Za-z\s]{3,40}$/", $_POST['name'])) {
$errors[] = "Invalid name format.";
}
// Email validation
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$errors[] = "Invalid email.";
}
// Phone validation
if (!preg_match("/^98\d{8}$/", $_POST['phone'])) {
$errors[] = "Invalid phone number.";
}
// Password validation
if (strlen($_POST['password']) < 8 || !preg_match("/[0-9]/", $_POST['password'])) {
$errors[] = "Password must be 8+ chars with at least 1 number.";
}
if (!empty($errors)) {
die("Errors: " . implode("<br>", $errors));
}
// Proceed to database insertion (with PDO!)
Database Table (MySQL):
CREATE TABLE bca_applicants (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(40) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(10) NOT NULL,
password VARCHAR(255) NOT NULL, -- Store hashed passwords!
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Real-World Tie-In:
- TU’s online exam system uses similar validation to reject malformed submissions (e.g., non-numeric roll numbers).
5. Security Best Practices
| Threat | Prevention | Example |
|---|---|---|
| SQLi | Use PDO/prepared statements | $stmt->execute(['user' => $input]) |
| XSS | Escape output (htmlspecialchars) |
echo htmlspecialchars($data) |
| CSRF | CSRF tokens in forms | <input type="hidden" name="token"> |
| File Uploads | Validate file types/sizes | if ($_FILES['file']['type'] != 'image/jpeg') |
| Brute Force | Rate limiting (e.g., 5 attempts/minute) | if ($attempts > 5) { blockIP(); } |
6. AJAX Validation Example (Phone Availability Check)
Use Case: Check if a phone number is already registered (e.g., Ncell’s SIM registration).
HTML:
<input type="tel" id="phone" placeholder="Phone">
<div id="phoneStatus"></div>
JavaScript (AJAX):
document.getElementById("phone").addEventListener("blur", function() {
const phone = this.value;
fetch("check_phone.php", {
method: "POST",
body: `phone=${phone}`
})
.then(response => response.text())
.then(data => {
document.getElementById("phoneStatus").innerHTML =
data === "available" ? "✅ Available" : "❌ Taken";
});
});
PHP (check_phone.php):
$pdo = new PDO("mysql:host=localhost;dbname=FOHSS", "user", "pass");
$stmt = $pdo->prepare("SELECT COUNT(*) FROM users WHERE phone = :phone");
$stmt->execute(['phone' => $_POST['phone']]);
$count = $stmt->fetchColumn();
echo $count > 0 ? "taken" : "available";
Visual:
sequenceDiagram
User->>Browser: Enters phone (e.g., 9812345678)
Browser->>Server: AJAX POST to check_phone.php
Server->>Database: Query COUNT(phone)
Database-->>Server: 1 (exists)
Server-->>Browser: "taken"
Browser->>User: Displays "❌ Taken"Real-World Use:
- Pathao’s driver signup uses AJAX to check if a phone number is already registered before proceeding.
In the Real World
eSewa’s Payment Form
- Validation: Client-side checks for valid phone numbers (10 digits, starts with 98) and card expiry dates.
- Security: Server-side uses
filter_var()and PCI-compliant tokenization to prevent credit card theft.
Daraz’s Order Queue
- Validation: Rejects orders with invalid product IDs or quantities (e.g., negative numbers).
- Security: CSRF tokens prevent unauthorized order modifications.
Ncell’s SIM Registration
- AJAX Validation: Checks phone availability in real-time before processing the application.
- SQLi Protection: Uses PDO to avoid SQL injection in the
SELECT * FROM sim_applicants WHERE phone = ?query.
Exam Tip
- Always validate on both client and server. Client-side for UX; server-side for security.
- Use PDO for database queries. Never concatenate user input into SQL strings.
- Escape output. Use
htmlspecialchars()for all dynamic content. - For forms:
- HTML: Use
required,pattern, andtype="email"attributes. - JavaScript: Validate on
blur/submitevents. - PHP: Use
filter_var()andpreg_match().
- HTML: Use
- Common exam questions:
- Write a form with validation for name (3–40 chars), email, and phone (Nepali format).
- Explain how to prevent SQLi/XSS in a login form.
- Design an AJAX-based phone availability checker.
- Code traces are key! Show step-by-step execution (e.g., how
filter_var()processes an email) in your answers.
Final Note:
"Security is not a feature; it’s the foundation. A single unvalidated input can cost a company millions (e.g., Yahoo’s 2013 breach). Always validate, sanitize, and escape." — OWASP (Open Web Application Security Project)
Based on the TU BCA syllabus for Scripting Language (CACS254), unit 11.
Discussion
Loading…