wordpress-security-validation

安装量: 235
排名: #8976

安装

npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill wordpress-security-validation

WordPress Security & Data Validation

Version: 1.0.0 Target: WordPress 6.7+ | PHP 8.3+ Skill Level: Intermediate to Advanced

Overview

Security is not optional in WordPress development—it's fundamental. This skill teaches the three-layer security model that prevents XSS, CSRF, SQL injection, and other common web vulnerabilities through proper input sanitization, business logic validation, and output escaping.

The Golden Rule: "Sanitize on input, validate for logic, escape on output."

Why This Matters

Every year, thousands of WordPress sites are compromised due to security vulnerabilities in plugins and themes. Most of these attacks exploit one of three weaknesses:

XSS (Cross-Site Scripting): Malicious JavaScript injected through unsanitized output CSRF (Cross-Site Request Forgery): Unauthorized actions performed on behalf of authenticated users SQL Injection: Database manipulation through unsanitized database queries

This skill provides complete, production-ready patterns for preventing all three attack vectors.

The Three-Layer Security Model

WordPress security follows a defense-in-depth strategy with three distinct layers:

User Input → [1. SANITIZE] → [2. VALIDATE] → Process → [3. ESCAPE] → Output

Layer 1: Sanitization (Input Cleaning)

Purpose: Remove dangerous characters and normalize data format When: Immediately upon receiving user input Example: sanitize_text_field($_POST['username'])

Layer 2: Validation (Logic Checks)

Purpose: Ensure data meets business requirements When: After sanitization, before processing Example: if (!is_email($email)) { / error / }

Layer 3: Escaping (Output Protection)

Purpose: Prevent XSS by encoding special characters When: Every time you output data to browser Example: echo esc_html($user_input);

Critical Distinction:

Sanitization removes/transforms invalid data (changes the value) Validation checks if data is acceptable (returns true/false) Escaping makes data safe for display (context-specific encoding) 1. Nonces: CSRF Protection What Are Nonces?

Nonces (Numbers Used Once) are cryptographic tokens that verify a request originated from your site, not a malicious external source. They prevent Cross-Site Request Forgery (CSRF) attacks.

How CSRF Attacks Work:

How Nonces Prevent CSRF:

Nonce Implementation Patterns Pattern 1: Form Nonces (Most Common)

BEFORE (Vulnerable):

// Vulnerable form processing if (isset($_POST['submit'])) { $user_id = absint($_POST['user_id']); delete_user($user_id); // ⚠️ CSRF vulnerable! }

AFTER (Secure):

// Generate nonce in form

// Verify nonce on submission if (isset($_POST['submit'])) { // Security check #1: Verify nonce if (!isset($_POST['delete_user_nonce']) || !wp_verify_nonce($_POST['delete_user_nonce'], 'delete_user_action')) { wp_die('Security check failed: Invalid nonce'); }

// Security check #2: Capability check
if (!current_user_can('delete_users')) {
    wp_die('You do not have permission to delete users');
}

// Now safe to process
$user_id = absint($_POST['user_id']);
wp_delete_user($user_id);

}

Key Functions:

wp_nonce_field($action, $name) - Generates hidden nonce field wp_verify_nonce($nonce, $action) - Verifies nonce validity Pattern 2: URL Nonces

Use Case: Delete/trash links, admin actions

// Generate nonce URL $delete_url = wp_nonce_url( admin_url('admin.php?action=delete_post&post_id=123'), 'delete_post_123', // Action (must be unique) 'delete_nonce' // Query parameter name );

echo 'Delete Post';

// Verify nonce in handler add_action('admin_action_delete_post', 'handle_delete_post'); function handle_delete_post() { // Verify nonce from URL if (!isset($_GET['delete_nonce']) || !wp_verify_nonce($_GET['delete_nonce'], 'delete_post_123')) { wp_die('Invalid security token'); }

// Verify capability
$post_id = absint($_GET['post_id']);
if (!current_user_can('delete_post', $post_id)) {
    wp_die('You cannot delete this post');
}

// Delete post
wp_delete_post($post_id, true); // true = force delete

// Redirect with success message
wp_redirect(add_query_arg('message', 'deleted', wp_get_referer()));
exit;

}

Pattern 3: AJAX Nonces

Use Case: Frontend AJAX requests

BEFORE (Vulnerable):

// ⚠️ Vulnerable AJAX request jQuery.post(ajaxurl, { action: 'update_user_meta', user_id: 42, meta_key: 'favorite_color', meta_value: 'blue' }, function(response) { console.log(response); });

AFTER (Secure):

PHP (Enqueue script with nonce):

add_action('wp_enqueue_scripts', 'enqueue_ajax_script'); function enqueue_ajax_script() { wp_enqueue_script('my-ajax-script', plugin_dir_url(FILE) . 'js/ajax.js', ['jquery'], '1.0.0', true );

// Pass nonce and AJAX URL to JavaScript
wp_localize_script('my-ajax-script', 'myAjax', [
    'ajaxurl' => admin_url('admin-ajax.php'),
    'nonce' => wp_create_nonce('my_ajax_nonce'), // Generate nonce
]);

}

// AJAX handler with nonce verification add_action('wp_ajax_update_user_meta', 'handle_ajax_update'); function handle_ajax_update() { // Verify nonce check_ajax_referer('my_ajax_nonce', 'nonce');

// Verify capability
if (!current_user_can('edit_users')) {
    wp_send_json_error(['message' => 'Permission denied']);
}

// Sanitize input
$user_id = absint($_POST['user_id']);
$meta_key = sanitize_key($_POST['meta_key']);
$meta_value = sanitize_text_field($_POST['meta_value']);

// Update meta
update_user_meta($user_id, $meta_key, $meta_value);

wp_send_json_success(['message' => 'Updated successfully']);

}

JavaScript (Use nonce in AJAX):

jQuery(document).ready(function($) { $('#update-button').on('click', function() { $.post(myAjax.ajaxurl, { action: 'update_user_meta', nonce: myAjax.nonce, // Include nonce user_id: 42, meta_key: 'favorite_color', meta_value: 'blue' }, function(response) { if (response.success) { console.log(response.data.message); } else { console.error(response.data.message); } }); }); });

Key Functions:

wp_create_nonce($action) - Generate nonce token check_ajax_referer($action, $query_arg) - Verify AJAX nonce (dies on failure) wp_send_json_success($data) - Send JSON success response wp_send_json_error($data) - Send JSON error response Nonce Best Practices

✅ DO:

Use unique action names (e.g., delete_post_$post_id, not just delete) Always verify nonces BEFORE processing any data Combine nonce checks with capability checks Use specific nonce functions (check_ajax_referer for AJAX)

❌ DON'T:

Reuse the same nonce action for multiple operations Skip nonce verification for "read-only" operations Trust nonce verification alone (always check capabilities too) Store nonces in cookies or URLs for long-term use (they expire)

Nonce Lifespan: WordPress nonces expire after 24 hours by default (12 hours in each direction due to time window).

  1. Sanitization Functions Reference

Sanitization transforms user input into a safe format by removing or encoding dangerous characters. It's the first line of defense against malicious data.

Core Sanitization Functions Function Use Case Example Input Output sanitize_text_field() Single-line text (usernames, titles) "Hello <script>alert('xss')</script>" "Hello alert('xss')" sanitize_email() Email addresses "user@example.com<script>" "user@example.com" sanitize_url() / esc_url_raw() URLs (for storage) "javascript:alert('xss')" "" (blocked) sanitize_key() Array keys, meta keys "my key!" "my_key" sanitize_file_name() File uploads "../../etc/passwd" "..etcpasswd" absint() Positive integers "-5", "42abc" 5, 42 intval() Any integer "-5", "42.7" -5, 42 floatval() Floating-point numbers "3.14abc" 3.14 wp_kses_post() HTML content (allows safe tags) "

Safe

<script>Bad</script>" "

Safe

" wp_kses() HTML with custom allowed tags See below Custom filtering sanitize_textarea_field() Multi-line text "Line 1\nLine 2<script>" "Line 1\nLine 2" sanitize_title() Post slugs "Hello World!" "hello-world" Detailed Examples Text Sanitization // Single-line text (removes HTML, line breaks, extra whitespace) $username = sanitize_text_field($_POST['username']); // Input: " John Doe\n" // Output: "John Doe"

// Multi-line text (preserves line breaks, removes HTML) $bio = sanitize_textarea_field($_POST['bio']); // Input: "Line 1\nLine 2<script>alert('xss')</script>" // Output: "Line 1\nLine 2alert('xss')"

// Email (validates format and removes invalid characters) $email = sanitize_email($_POST['email']); // Input: "user@EXAMPLE.com <script>" // Output: "user@example.com"

// URL (removes dangerous protocols) $website = esc_url_raw($_POST['website']); // Input: "javascript:alert('xss')" // Output: "" (blocked protocol) // Input: "http://example.com" // Output: "http://example.com"

Numeric Sanitization // Positive integers only (absolute value) $post_id = absint($_POST['post_id']); // Input: "-5", "42", "123abc" // Output: 5, 42, 123

// Any integer (preserves negative) $temperature = intval($_POST['temperature']); // Input: "-5", "42.7", "99abc" // Output: -5, 42, 99

// Floating-point numbers $price = floatval($_POST['price']); // Input: "19.99", "20.5abc" // Output: 19.99, 20.5

HTML Sanitization

wp_kses_post() - Allow WordPress Post Editor Tags:

$content = wp_kses_post($_POST['content']); // Allows:

, , , ,