CACS254 Scripting Language

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() and filter_input() to validate emails, numbers, and URLs before processing.
  • JavaScript Events: onblur, onsubmit, and onchange trigger validation dynamically for instant feedback.
  • Security Headers: Content-Security-Policy and X-XSS-Protection headers 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_CARD to 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: &lt;script&gt;alert(&#039;XSS&#039;)&lt;/script&gt;

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

  1. 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.
  2. Daraz’s Order Queue

    • Validation: Rejects orders with invalid product IDs or quantities (e.g., negative numbers).
    • Security: CSRF tokens prevent unauthorized order modifications.
  3. 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

  1. Always validate on both client and server. Client-side for UX; server-side for security.
  2. Use PDO for database queries. Never concatenate user input into SQL strings.
  3. Escape output. Use htmlspecialchars() for all dynamic content.
  4. For forms:
    • HTML: Use required, pattern, and type="email" attributes.
    • JavaScript: Validate on blur/submit events.
    • PHP: Use filter_var() and preg_match().
  5. 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.
  6. 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…