~/icsd.ir — bash
SYSTEM_ONLINE

🔒 فصل ۱۳: امنیت و عملکرد وردپرس

وردپرس به‌خاطر محبوبیتش، هدف اصلی هکرهاست. توی این فصل یاد می‌گیریم چطور سایت رو امن کنیم و سرعتش رو چند برابر کنیم - دو ستون موفقیت هر سایت حرفه‌ای.

وردپرس به‌خاطر محبوبیتش، هدف اصلی هکرهاست. توی این فصل یاد می‌گیریم چطور سایت رو امن کنیم و سرعتش رو چند برابر کنیم – دو ستون موفقیت هر سایت حرفه‌ای.

🛡 اصول طلایی امنیت

⚠️

قوانین که هرگز نقض نکن

هر ورودی کاربر نامعتبره تا اعتبارسنجی نشه. هر خروجی باید escape بشه. هر اقدام مهم نیاز به nonce داره. هرگز SQL injection رو نادیده نگیر.

چک‌لیست امنیت اولیه

  • هیچ‌وقت کاربری به نام admin نداشته باش
  • رمز عبور قوی (۱۶+ کاراکتر) با اعداد، حروف بزرگ/کوچک و نماد
  • احراز دو مرحله‌ای (2FA) فعال باشه
  • HTTPS اجباری باشه (با Let’s Encrypt رایگان)
  • وردپرس و افزونه‌ها همیشه به‌روز
  • پشتیبان‌گیری روزانه به فضای خارج از سرور
  • محدودیت تلاش ورود (Limit Login Attempts)
  • فایروال (Wordfence یا iThemes Security)
  • اسکن ماهانه بدافزار
  • پیشوند جدول از wp_ تغییر کرده باشه

🧹 پاک‌سازی (Sanitize) و خروجی امن (Escape)

یه قانون ساده: Sanitize on input, Escape on output. هر داده که وارد سیستم می‌شه باید پاک‌سازی بشه، و هر داده که نمایش داده می‌شه باید escape بشه.

توابع پاک‌سازی (sanitize_*)

sanitize functions
// متن ساده (یه خطی)
$name = sanitize_text_field( $_POST['name'] );

// ایمیل
$email = sanitize_email( $_POST['email'] );

// متن چندخطی
$bio = sanitize_textarea_field( $_POST['bio'] );

// URL برای ذخیره در DB
$website = esc_url_raw( $_POST['website'] );

// عدد صحیح مثبت
$count = absint( $_POST['count'] );

// عدد صحیح (می‌تونه منفی باشه)
$value = intval( $_POST['value'] );

// عدد اعشاری
$price = floatval( $_POST['price'] );

// HTML امن (با تگ‌های مجاز)
$content = wp_kses_post( $_POST['content'] );

// HTML با تگ‌های دلخواه
$html = wp_kses( $_POST['html'], array(
    'a'      => array( 'href' => array(), 'title' => array() ),
    'br'     => array(),
    'em'     => array(),
    'strong' => array(),
) );

// Slug (نام انگلیسی URL-friendly)
$slug = sanitize_title( $_POST['slug'] );

// Key (فقط حروف، عدد، خط تیره و آندرلاین)
$key = sanitize_key( $_POST['key'] );

// نام فایل
$filename = sanitize_file_name( $_POST['file'] );

// رنگ هگز
$color = sanitize_hex_color( $_POST['color'] );

// شماره تلفن
$phone = preg_replace( '/[^0-9+]/', '', $_POST['phone'] );

توابع Escape (esc_*)

escape functions
// در HTML معمولی
echo esc_html( $title );

// در attribute
echo '<input value="' . esc_attr( $value ) . '">';

// در href یا src
echo '<a href="' . esc_url( $link ) . '">Click</a>';

// در textarea
echo '<textarea>' . esc_textarea( $content ) . '</textarea>';

// در JavaScript
echo '<script>var name = "' . esc_js( $name ) . '";</script>';

// HTML با تگ‌های مجاز
echo wp_kses_post( $rich_content );

// با ترجمه
echo esc_html__( 'Hello', 'textdomain' );  // ترجمه + escape
esc_html_e( 'Hello', 'textdomain' );        // مستقیم چاپ
⚠️

اشتباه رایج

هرگز echo $variable بدون escape ننویس. حتی اگه فکر می‌کنی متغیر امنه، احتمال داره از منبع غیرامن اومده باشه.

SQL injection – استفاده از prepare

$wpdb->prepare
global $wpdb;

// ❌ آسیب‌پذیر
$results = $wpdb->get_results( 
    "SELECT * FROM {$wpdb->prefix}orders WHERE user_id = $user_id" 
);

// ✅ امن
$results = $wpdb->get_results( $wpdb->prepare(
    "SELECT * FROM {$wpdb->prefix}orders WHERE user_id = %d AND status = %s",
    $user_id,
    $status
) );

// placeholder ها:
// %d = integer
// %f = float
// %s = string

// IN clause با تعداد متغیر
$ids = array( 1, 2, 3, 4 );
$placeholders = implode( ', ', array_fill( 0, count( $ids ), '%d' ) );
$query = $wpdb->prepare(
    "SELECT * FROM table WHERE id IN ($placeholders)",
    ...$ids
);

🎫 Nonces – جلوگیری از CSRF

CSRF (Cross-Site Request Forgery) یعنی کسی از طرف کاربر بدون اطلاعش درخواست بفرسته. nonce یه توکن یک‌بار مصرفه که این حمله رو خنثی می‌کنه.

در فرم

nonce in form
<form method="post">
    <?php wp_nonce_field( 'save_settings', '_settings_nonce' ); ?>
    <input type="text" name="my_field">
    <input type="submit">
</form>

در پردازش

verify nonce
// روش ۱: اگه نباشه die می‌کنه
check_admin_referer( 'save_settings', '_settings_nonce' );

// روش ۲: دستی چک کن
if ( ! isset( $_POST['_settings_nonce'] ) || 
     ! wp_verify_nonce( $_POST['_settings_nonce'], 'save_settings' ) ) {
    wp_die( 'درخواست نامعتبر' );
}

// در AJAX
check_ajax_referer( 'my_ajax_action', 'security' );

در URL

nonce in URL
// ساخت URL با nonce
$url = wp_nonce_url(
    admin_url( 'admin.php?action=delete&id=123' ),
    'delete_item_123'
);

// در پردازش
if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'delete_item_123' ) ) {
    wp_die( 'دسترسی غیرمجاز' );
}

🔐 امن‌سازی wp-config.php

wp-config.php – بخش امنیت
// ۱. کلیدهای امنیتی - از https://api.wordpress.org/secret-key/1.1/salt/
define( 'AUTH_KEY',         'long-random-string-here' );
define( 'SECURE_AUTH_KEY',  'long-random-string-here' );
define( 'LOGGED_IN_KEY',    'long-random-string-here' );
define( 'NONCE_KEY',        'long-random-string-here' );
define( 'AUTH_SALT',        'long-random-string-here' );
define( 'SECURE_AUTH_SALT', 'long-random-string-here' );
define( 'LOGGED_IN_SALT',   'long-random-string-here' );
define( 'NONCE_SALT',       'long-random-string-here' );

// ۲. غیرفعال کردن ویرایش فایل از پنل
define( 'DISALLOW_FILE_EDIT', true );

// ۳. غیرفعال کردن نصب/حذف افزونه از پنل (سایت‌های پروداکشن)
define( 'DISALLOW_FILE_MODS', true );

// ۴. اجبار HTTPS برای ادمین
define( 'FORCE_SSL_ADMIN', true );

// ۵. آپدیت خودکار هسته (فقط minor)
define( 'WP_AUTO_UPDATE_CORE', 'minor' );

// ۶. مخفی کردن خطاهای PHP در پروداکشن
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', true );

// ۷. افزایش حافظه PHP
define( 'WP_MEMORY_LIMIT', '256M' );

// ۸. محدود کردن نسخه‌های Revision
define( 'WP_POST_REVISIONS', 5 );

// ۹. کاهش بازه auto-save
define( 'AUTOSAVE_INTERVAL', 300 ); // ۵ دقیقه

// ۱۰. پاکسازی Trash
define( 'EMPTY_TRASH_DAYS', 7 );

محافظت از wp-config.php با .htaccess

.htaccess
# محافظت از wp-config.php
<Files wp-config.php>
    order allow,deny
    deny from all
</Files>

# محافظت از .htaccess خودش
<Files .htaccess>
    order allow,deny
    deny from all
</Files>

# جلوگیری از نمایش دایرکتوری
Options -Indexes

# جلوگیری از ورود به wp-includes
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>

# محافظت از xmlrpc.php (اگه استفاده نمی‌کنی)
<Files xmlrpc.php>
    order deny,allow
    deny from all
</Files>

📡 Security Headers

هدرهای HTTP که امنیت رو در سطح مرورگر افزایش می‌دن:

.htaccess – Security Headers
<IfModule mod_headers.c>
    # جلوگیری از Clickjacking
    Header set X-Frame-Options "SAMEORIGIN"
    
    # جلوگیری از MIME-sniffing
    Header set X-Content-Type-Options "nosniff"
    
    # XSS Protection (مرورگرهای قدیمی)
    Header set X-XSS-Protection "1; mode=block"
    
    # Referrer Policy
    Header set Referrer-Policy "strict-origin-when-cross-origin"
    
    # HSTS - اجبار HTTPS
    Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    
    # Content Security Policy
    Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:;"
    
    # Permissions Policy
    Header set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    
    # حذف هدر اطلاعات سرور
    Header unset X-Powered-By
    Header unset Server
</IfModule>
🔍

تست هدرها

بعد از اعمال، با securityheaders.com امتیاز سایتت رو چک کن. هدف A یا A+!

⚡ سیستم کش

کش یعنی نگه داشتن خروجی محاسبه‌شده تا دفعه بعد سریع‌تر تحویل داده بشه. سرعت سایت رو ۲ تا ۱۰ برابر می‌کنه.

انواع کش

نوع کش چی رو کش می‌کنه؟ ابزار
Page Cache HTML کامل صفحه WP Rocket, W3 Total Cache
Object Cache نتایج کوئری دیتابیس Redis, Memcached
Browser Cache CSS, JS, تصاویر در مرورگر هدرهای HTTP
OPcache کد کامپایل‌شده PHP پیش‌فرض PHP 7+
CDN Cache محتوای استاتیک نزدیک کاربر Cloudflare, ArvanCloud

Browser Cache در .htaccess

.htaccess
<IfModule mod_expires.c>
    ExpiresActive On
    
    # تصاویر - یک سال
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"
    
    # CSS و JS - یک ماه
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    
    # فونت - یک سال
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType font/woff "access plus 1 year"
    
    # HTML - بدون کش
    ExpiresByType text/html "access plus 0 seconds"
</IfModule>

# GZIP فشرده‌سازی
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css text/javascript application/javascript application/json
</IfModule>

⏱ Transients API

ساده‌ترین راه برای کش کردن داده در وردپرس. مثل Cache.set() در زبان‌های دیگه.

transients
// ذخیره با مدت زمان
set_transient( 'my_data', $data, HOUR_IN_SECONDS );

// مدت‌ها:
// MINUTE_IN_SECONDS  = 60
// HOUR_IN_SECONDS    = 3600
// DAY_IN_SECONDS     = 86400
// WEEK_IN_SECONDS    = 604800
// MONTH_IN_SECONDS   = 2592000
// YEAR_IN_SECONDS    = 31536000

// خوندن
$data = get_transient( 'my_data' );
if ( false === $data ) {
    // محاسبه دوباره و ذخیره
    $data = expensive_calculation();
    set_transient( 'my_data', $data, HOUR_IN_SECONDS );
}

// حذف
delete_transient( 'my_data' );

مثال واقعی – کش کردن آمار سایت

site stats with cache
function get_site_stats() {
    $stats = get_transient( 'site_stats' );
    
    if ( false === $stats ) {
        // کوئری‌های سنگین
        $stats = array(
            'posts'    => wp_count_posts()->publish,
            'comments' => wp_count_comments()->approved,
            'users'    => count_users()['total_users'],
            'products' => wp_count_posts( 'product' )->publish,
        );
        
        // ۶ ساعت کش
        set_transient( 'site_stats', $stats, 6 * HOUR_IN_SECONDS );
    }
    
    return $stats;
}

// پاک کردن کش وقتی نوشته جدید منتشر شد
add_action( 'publish_post', function() {
    delete_transient( 'site_stats' );
} );

برای پروژه‌های ICSD

توی WooCommerce Advanced Reports که خودت ساختی، استفاده از Transients می‌تونه گزارش‌های سنگین رو ۱۰ برابر سریع‌تر کنه. مخصوصاً برای محاسبات روزانه/ماهانه.

🚀 بهینه‌سازی پیشرفته

۱. غیرفعال کردن قابلیت‌های اضافی

functions.php
// حذف emoji
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );

// حذف فید RSS اضافی
remove_action( 'wp_head', 'feed_links_extra', 3 );

// حذف لینک‌های مدیریت ویندوز
remove_action( 'wp_head', 'wlwmanifest_link' );
remove_action( 'wp_head', 'rsd_link' );

// حذف نسخه وردپرس
remove_action( 'wp_head', 'wp_generator' );

// حذف لینک‌های REST API و oEmbed (اگه نیاز نداری)
remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );

// غیرفعال کردن XML-RPC
add_filter( 'xmlrpc_enabled', '__return_false' );

// غیرفعال کردن Heartbeat در فرانت
add_action( 'init', function() {
    if ( ! is_admin() ) {
        wp_deregister_script( 'heartbeat' );
    }
} );

// کاهش فرکانس Heartbeat در ادمین
add_filter( 'heartbeat_settings', function( $settings ) {
    $settings['interval'] = 60; // به جای ۱۵ ثانیه
    return $settings;
} );

۲. بهینه‌سازی دیتابیس

SQL queries
// پاک کردن revision های قدیمی (اجرا در phpMyAdmin)
DELETE FROM wp_posts WHERE post_type = 'revision';

// پاک کردن نوشته‌های Trash
DELETE FROM wp_posts WHERE post_status = 'trash';

// پاک کردن دیدگاه‌های اسپم
DELETE FROM wp_comments WHERE comment_approved = 'spam';

// پاک کردن metadata یتیم
DELETE pm FROM wp_postmeta pm 
LEFT JOIN wp_posts wp ON wp.ID = pm.post_id 
WHERE wp.ID IS NULL;

// پاک کردن transient های منقضی
DELETE FROM wp_options 
WHERE option_name LIKE '_transient_timeout_%' 
AND option_value < UNIX_TIMESTAMP();

// بهینه‌سازی جدول‌ها
OPTIMIZE TABLE wp_posts, wp_postmeta, wp_options, wp_comments;

۳. بهینه‌سازی تصاویر

  • WebP و AVIF: فرمت‌های مدرن با حجم ۳۰-۵۰٪ کمتر از JPG
  • Lazy Loading: از وردپرس ۵.۵ به بعد به‌صورت پیش‌فرض
  • اندازه مناسب: از srcset استفاده کن
  • افزونه‌ها: ShortPixel, Smush, EWWW Image Optimizer

۴. حذف اسکریپت‌های اضافی از صفحات خاص

conditional dequeue
// حذف ووکامرس از صفحاتی که نیاز نداره
add_action( 'wp_enqueue_scripts', function() {
    if ( ! is_woocommerce() && ! is_cart() && ! is_checkout() ) {
        wp_dequeue_style( 'woocommerce-general' );
        wp_dequeue_style( 'woocommerce-layout' );
        wp_dequeue_style( 'woocommerce-smallscreen' );
        wp_dequeue_script( 'wc-cart-fragments' );
    }
}, 99 );

// حذف Contact Form 7 از همه صفحات به‌جز برگه تماس
add_action( 'wp_enqueue_scripts', function() {
    if ( ! is_page( 'contact' ) ) {
        wp_dequeue_script( 'contact-form-7' );
        wp_dequeue_style( 'contact-form-7' );
    }
}, 99 );

۵. ابزارهای اندازه‌گیری

اهداف عملکرد

  • زمان لود اولیه: کمتر از ۲ ثانیه
  • LCP (Largest Contentful Paint): کمتر از ۲.۵ ثانیه
  • CLS (Cumulative Layout Shift): کمتر از ۰.۱
  • INP (Interaction to Next Paint): کمتر از ۲۰۰ms
  • تعداد درخواست‌ها: کمتر از ۵۰
  • حجم کل صفحه: کمتر از ۲ مگابایت

🎯 مثال واقعی

پیشرفته

راه‌اندازی Redis Object Cache

برای سایت‌های پرترافیک، Redis چندبرابر سرعت رو افزایش می‌ده:

  1. Redis رو روی سرور نصب کن
  2. افزونه Redis Object Cache رو نصب کن
  3. توی wp-config.php اضافه کن:
wp-config.php
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_CACHE_KEY_SALT', 'icsd_' ); // یکتا برای هر سایت

۴. توی پنل، گزینه «Enable Object Cache» رو بزن

📝 خلاصه فصل

  • هر ورودی sanitize، هر خروجی escape
  • nonce برای جلوگیری از CSRF
  • $wpdb->prepare برای جلوگیری از SQL injection
  • Security Headers برای امنیت در سطح مرورگر
  • Transients API برای کش‌گذاری ساده
  • Browser cache و GZIP در .htaccess
  • تصاویر رو بهینه کن (WebP، lazy loading)
  • Query Monitor برای پیدا کردن گلوگاه‌ها

نمایش سایت

رنگ سایت
حالت نمایش
اندازهٔ متن
خوانایی

این تنظیمات فقط روی مرورگر شما ذخیره می‌شود.