التهديد

إذا سبق لك أن رأيت طلبًا غريبًا كهذا ?action=save_settings&data=… في سجلاتك، ربما تكون قد صادفت السيناريو الأكثر شيوعًا في عام 2026 على ووردبريس: إجراء AJAX أو REST "عملي" ينتهي بفتح باب خلفي.

نادراً ما تنشأ المشكلة من نواة ووردبريس 6.9.4. في تجربتي، تبدأ المشكلة دائماً تقريباً من إضافة مقتطف برمجي "بسرعة" (ملف functions.php، أو إضافة مقتطفات برمجية، أو إضافة mu-plugin) أو إضافة صغيرة مُخصصة: كغياب قيمة nonce، أو نسيان التحقق من السعة، أو تساهل مفرط في التحقق من صحة المدخلات.

من الناحية العملية، إذا تم الكشف عن إجراء حساس (تحديث الخيارات، كتابة الملفات، استيراد المحتوى، تنفيذ الاستعلامات) دون وجود ضمانات، فيمكن للمهاجم ما يلي:

  • خيارات التعديل (البريد الإلكتروني مشرف(عنوان الموقع، إعدادات تحسين محركات البحث، مفاتيح واجهة برمجة التطبيقات) لاختطاف الموقع؛
  • إنشاء حساب مسؤول عبر نقطة نهاية ضعيفة الحماية؛
  • حقن المحتوى (البريد العشوائي، والروابط، والبرامج النصية) مما يؤدي إلى تدهور تحسين محركات البحث والسمعة؛
  • يؤدي إلى تنفيذ تعليمات برمجية عن بعد غير مباشر (على سبيل المثال، كتابة ملف PHP عبر استيراد غير مُصفّى، أو تحميل "قالب" مُتحكّم به)؛
  • استخراج البيانات (رسائل البريد الإلكتروني، طلبات WooCommerce، النماذج) إذا كانت نقطة النهاية تُرجع الكثير من المعلومات.

يختلف التكرار الفعلي حسب نطاق الهجوم (المكونات الإضافية، نقاط النهاية العامة، النماذج). تستهدف عمليات الفحص الآلية بشكل أساسي ما يلي:

  • مسارات REST المخصصة التي تم التحقق من صحتها بشكل غير صحيح؛
  • الإجراءات ليه wp_ajax_nopriv_* الذين يفعلون أكثر من مجرد "القراءة"؛
  • نماذج الواجهة الأمامية التي تكتب إلى قاعدة البيانات بدون قيمة عشوائية (nonce)؛
  • عمليات استيراد ملفات CSV/JSON "خاصة بالمسؤولين فقط" ولكن يمكن الوصول إليها بدون التحكم في السعة.

المخاطرة، بعبارات بسيطة: تظن أنك أنشأت زر "حفظ".لكنك أحيانًا قد أنشأت نموذج تكوين عام متاح للجميع، بما في ذلك الروبوتات.

ملخص سريع

  • قيمة عشوائية + سعة يجب أن يستوفي أي إجراء يُعدِّل أي شيء شرطًا من شروط القيمة العشوائية (nonce). et سعة (على سبيل المثال) manage_options).
  • REST > admin-ajax للتطورات الجديدة: مصادقة واضحة، مخطط حجج، استجابات موحدة.
  • تعقيم عند المدخل، وتحقق صارم من الهوية، وهروب عند المخرج ثلاث خطوات مختلفة، يتم تطبيقها في المكان الصحيح.
  • لا تقم بتخزين ملفات HTML/JS "المجانية" الاختيارية. إذا لم تتحكم في من يمكنه الكتابة (XSS المخزن الكلاسيكي).
  • قم بتحصين الخادم تعطيل تحرير الملفات، ومنع تنفيذ PHP في uploadsأضف العناوين.
  • قم بمراجعة نقاط النهاية الخاصة بك : بحث wp_ajax_nopriv, register_rest_route et update_option في الكود الخاص بك.

الكود المعرض للثغرات الأمنية - ما لا يجب فعله

مثال واقعي: يقوم مطور بإضافة خيار "حفظ" عبر admin-ajax.php للتحكم في إعلان ترويجي (نص + رابط) من واجهة المستخدم. يعمل هذا... إلى أن يكتشف أحدهم هذا الإجراء ويستبدل إعداداتك.

<?php
/**
 * Exemple VULNÉRABLE : ne copiez pas ça.
 * Problèmes :
 * - action accessible aux non-connectés (nopriv)
 * - pas de nonce
 * - pas de contrôle de capacité
 * - validation insuffisante
 */
add_action( 'wp_ajax_nopriv_bpcab_save_promo', 'bpcab_save_promo_vulnerable' );
add_action( 'wp_ajax_bpcab_save_promo', 'bpcab_save_promo_vulnerable' );

function bpcab_save_promo_vulnerable() {
	// Mauvaise idée : on fait confiance à $_POST
	$text = isset( $_POST['text'] ) ? $_POST['text'] : '';
	$url  = isset( $_POST['url'] ) ? $_POST['url'] : '';

	// Mauvaise idée : update_option sans garde-fous
	update_option( 'bpcab_promo_text', $text );
	update_option( 'bpcab_promo_url', $url );

	wp_send_json_success( array(
		'message' => 'OK',
	) );
}

إليكم ما يحدث خلف الكواليس:

  • الخطاف wp_ajax_nopriv_... يقوم بالفعل يمكن الوصول إليه دون الحاجة إلى تسجيل الدخول.
  • بدون السفير البابوييمكن لأي موقع أن يُطلق الطلب من متصفح الزائر (CSRF)، ويمكن لأي برنامج آلي أن يستدعيه مباشرة.
  • بدون فحص القدرات، حتى حساب المشترك (أو الحساب المخترق) يمكنه تعديل الإعدادات التي يجب أن تظل خاصة بالمسؤول فقط.
  • بدون التحقق، فإنك تفتح الباب أمام قيم غير متوقعة، وغالبًا ما تؤدي إلى XSS مخزنة ثم تقوم بعرض bpcab_promo_text بدون هروب صارم.

أحد الأخطاء الشائعة التي أراها هو نسخ الكود إلى functions.phpثم، يتعطل الكود بسبب نقص فاصلة أو فاصلة منقوطة. والنتيجة: شاشة بيضاء، ويعود الموقع إلى وضع "استكشاف الأخطاء وإصلاحها" إذا كان لديك خيار الاسترداد. في ووردبريس 6.9.4، يساعد وضع الاسترداد، لكنه لا يغني عن التحقق من صحة البيانات في وضع الاختبار.

الكود الآمن - التنفيذ الصحيح

بالنسبة لـ WordPress 6.9.4، أفضل استخدام REST بدلاً من admin-ajax.php بمجرد ضبط الإعدادات، ستحصل على حجة منظمة، واستجابات متسقة، ومصادقة أنظف.

الهدف: نفس الوظيفة (حفظ النص + عنوان URL)، ولكن مع:

  • المصادقة (تم تسجيل دخول المستخدم)؛
  • autorisation (قدرة) ؛
  • مناهضة استغلال الأزمات عبر الإنترنت (REST nonce)؛
  • التحقق من صحة (الأنواع، الأطوال، عنوان URL)؛
  • التعقيم (تنظيف)؛
  • استجابات الأخطاء قابل للاستخدام.

1) قم بتسجيل مسار REST باستخدام permission_callback

<?php
/**
 * Implémentation sécurisée (WordPress 6.9.4+, PHP 8.1+).
 * À placer dans un plugin (recommandé) ou un mu-plugin.
 */

add_action( 'rest_api_init', function () {
	register_rest_route(
		'bpcab/v1',
		'/promo',
		array(
			array(
				'methods'             => 'POST',
				'callback'            => 'bpcab_rest_save_promo',
				'permission_callback' => 'bpcab_rest_can_manage_promo',
				'args'                => array(
					'text' => array(
						'type'              => 'string',
						'required'          => true,
						'sanitize_callback' => 'sanitize_text_field',
						'validate_callback' => function ( $value ) {
							// Validation stricte : évite les payloads énormes et les surprises
							return is_string( $value ) && mb_strlen( $value ) >= 1 && mb_strlen( $value ) <= 140;
						},
					),
					'url'  => array(
						'type'              => 'string',
						'required'          => true,
						'sanitize_callback' => 'esc_url_raw',
						'validate_callback' => function ( $value ) {
							// Autorise uniquement http(s)
							if ( ! is_string( $value ) ) {
								return false;
							}
							$scheme = wp_parse_url( $value, PHP_URL_SCHEME );
							return in_array( $scheme, array( 'http', 'https' ), true );
						},
					),
				),
			),
		)
	);
} );

function bpcab_rest_can_manage_promo( WP_REST_Request $request ) : bool {
	// 1) L'utilisateur doit être connecté
	if ( ! is_user_logged_in() ) {
		return false;
	}

	// 2) Capacité : adaptez selon votre besoin (manage_options est un classique)
	return current_user_can( 'manage_options' );
}

شرح بسيط: الطريق موجودومع ذلك، سيرفض ووردبريس الطلب إذا لم يكن المستخدم مسجلاً دخوله أو لم يكن لديه الصلاحيات الصحيحة.

الشرح الفني: permission_callback يتم تقييمها قبل callbackهذا هو العائق الرئيسي الذي يواجهك من جانب التطبيق. args إنهم يفرضون عقدًا: النوع، والتنظيف، والتحقق. وهذا يقلل بشكل كبير من الأخطاء والحلول البديلة.

2) رد الاتصال: تحديث الخيارات، مع معالجة الأخطاء

<?php
function bpcab_rest_save_promo( WP_REST_Request $request ) : WP_REST_Response|WP_Error {
	$text = (string) $request->get_param( 'text' );
	$url  = (string) $request->get_param( 'url' );

	// Défense en profondeur : même si args valide, on reste prudent
	$text = sanitize_text_field( $text );
	$url  = esc_url_raw( $url );

	if ( '' === $text ) {
		return new WP_Error(
			'bpcab_invalid_text',
			'Le texte ne peut pas être vide.',
			array( 'status' => 400 )
		);
	}

	if ( empty( $url ) ) {
		return new WP_Error(
			'bpcab_invalid_url',
			'URL invalide.',
			array( 'status' => 400 )
		);
	}

	update_option( 'bpcab_promo_text', $text, false );
	update_option( 'bpcab_promo_url', $url, false );

	return new WP_REST_Response(
		array(
			'success' => true,
			'data'    => array(
				'text' => $text,
				'url'  => $url,
			),
		),
		200
	);
}

تفصيل مهم: المعامل الثالث لـ update_option ($autoload) ثابت عند falseلقد رأيت مواقع ويب تتباطأ بسبب قيام أحد الإضافات بتخزين عدد كبير جدًا من الخيارات في التحميل التلقائي. في الصفحات ذات الزيارات العالية، يؤثر هذا بشكل كبير على زمن استجابة الخادم (TTFB).

3) من جانب جافا سكريبت: REST nonce و fetch

لستَ مُطالبًا بنشر مثال عملي. لكنك تحتاج إلى استدعاء صحيح من جانب الواجهة الأمامية/لوحة التحكم. يتم استرداد قيمة REST nonce عبر wp_create_nonce( 'wp_rest' ) ويتم إرسالها في رأس الطلب X-WP-Nonce.

<?php
/**
 * Enqueue : charge un script et lui passe l'URL REST + nonce.
 * À utiliser dans l'admin, ou sur le front si nécessaire.
 */
add_action( 'admin_enqueue_scripts', function ( $hook ) {
	// Exemple : ne charger que sur une page d'options (à adapter)
	if ( 'settings_page_bpcab-promo' !== $hook ) {
		return;
	}

	wp_enqueue_script(
		'bpcab-promo',
		plugins_url( 'assets/promo.js', __FILE__ ),
		array(),
		'1.0.0',
		true
	);

	wp_localize_script(
		'bpcab-promo',
		'BPCAB_PROMO',
		array(
			'restUrl' => esc_url_raw( rest_url( 'bpcab/v1/promo' ) ),
			'nonce'   => wp_create_nonce( 'wp_rest' ),
		)
	);
} );
async function savePromo(text, url) {
  const res = await fetch(BPCAB_PROMO.restUrl, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-WP-Nonce': BPCAB_PROMO.nonce
    },
    body: JSON.stringify({ text, url })
  });

  const data = await res.json();
  if (!res.ok) {
    throw new Error(data?.message || 'Erreur lors de la sauvegarde');
  }
  return data;
}

الأخطاء الشائعة:

  • استعمال admin-ajax.php "بدافع العادة" ونسيان ذلك nopriv يكشف عن الفعل.
  • ضع الكود في الملف الخطأ (على سبيل المثال) functions.php (من السمة الرئيسية) ثم يفقدها في التحديث التالي.
  • نسيان مسح ذاكرة التخزين المؤقت (إضافة ذاكرة التخزين المؤقت، ذاكرة التخزين المؤقت للخادم، Cloudflare). أنت تختبر حلاً... لكنك ما زلت تستخدم ملف جافا سكريبت القديم.
  • اختبر مباشرةً في بيئة الإنتاج دون حفظ التغييرات. في مواقع Elementor/Divi/Avada، قد يتسبب خطأ فادح بسيط في PHP في تعطيل المحرر.

التوافق مع Divi 5 و Elementor و Avada

يعمل نمط REST هذا بشكل جيد مع أدوات إنشاء الصفحات لأنه لا يعتمد على عرض محدد:

  • ديفي 5 استخدم وحدة نمطية مخصصة أو "وحدة نمطية برمجية" لواجهة المستخدم، ولكن احتفظ بنسخة احتياطية على جانب REST. تجنب تخزين ملفات HTML اختيارية مجانية إذا كانت واجهة المستخدم متاحة لغير المسؤولين.
  • Elementor : إذا قمت بإنشاء عنصر واجهة مستخدم، فقم بتخزين التكوين عبر عناصر تحكم Elementor (التي تمر عبر المسؤول والقدرات)، واستخدم REST فقط للإجراءات الديناميكية.
  • فتح ينطبق المنطق نفسه على Fusion Builder. يجب أن تظل الإجراءات "المباشرة" مقتصرة على المسؤول فقط ومحمية بواسطة رمز عشوائي (nonce).

تكوين الخادم

يقلل الكود الآمن من المخاطر، لكن معظم الثغرات التي اضطررتُ إلى إصلاحها نتجت عن سلسلة من التفاعلات: إضافة برمجية ضعيفة + خادم متساهل. يُقلل تحصين الخادم من تأثير تعطل أحد المكونات.

ملف .htaccess (أباتشي): منع تنفيذ PHP في عمليات التحميل

إذا كان مزود خدمة الاستضافة الخاص بك يستخدم Apache و .htaccess إذا كان نشطًا، ضع هذا في wp-content/uploads/.htaccessالهدف: منع تنفيذ نصوص PHP المخزنة في الملفات المرفوعة.

# Créez/éditez wp-content/uploads/.htaccess (Apache)
# Bloque l'exécution des fichiers PHP dans uploads
<FilesMatch ".(php|phtml|phar)$">
  Require all denied
</FilesMatch>

حالة استثنائية: تقوم بعض الإضافات القديمة جدًا بتحميل "ملفات مساعدة" (وهي ممارسة غير سليمة). مع ووردبريس 6.9.4، تجنب هذا النوع من الإضافات. إذا لم يكن لديك خيار آخر، فاعزل الإضافة المتسببة في المشكلة ووثّق الاستثناء.

ملف .htaccess: لحماية ملف wp-config.php والملفات الحساسة

# Dans le .htaccess à la racine WordPress (Apache)
<Files wp-config.php>
  Require all denied
</Files>

<FilesMatch "^(readme.html|license.txt)$">
  Require all denied
</FilesMatch>

wp-config.php: تعطيل محرر الملفات

لا يمنع هذا النظام المهاجم الذي لديه بالفعل صلاحيات إدارية كاملة، ولكنه يقلل الضرر في الحالات التي يتم فيها الحصول على دور رفيع المستوى من خلال ثغرة أمنية.

<?php
// Désactive l'éditeur de fichiers dans l'admin (recommandé)
define( 'DISALLOW_FILE_EDIT', true );

// Optionnel : bloque aussi l'installation/MAJ via l'admin (à évaluer selon votre workflow)
// define( 'DISALLOW_FILE_MODS', true );

رؤوس HTTP (أباتشي): الحد من هجمات XSS/اختطاف النقرات

لا تمنع هذه العناوين الثغرات المنطقية، لكنها تحد من بعض آثارها. اختبر الموقع دائمًا بعد إضافتها، خاصةً إذا كان لديك إطارات iframe شرعية (مثل عمليات التكامل).

# Dans .htaccess (si mod_headers est actif)
<IfModule mod_headers.c>
  Header always set X-Content-Type-Options "nosniff"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
</IfModule>

بروتوكول HTTPS وملفات تعريف الارتباط

إذا كان موقعك يستخدم بروتوكول HTTPS بنسبة 100% (وهو ما ينبغي أن يكون عليه الحال بحلول عام 2026)، فقم بفرض استخدام SSL لمنطقة الإدارة:

<?php
// Force SSL sur /wp-admin (si votre HTTPS est correctement configuré)
define( 'FORCE_SSL_ADMIN', true );

تحقق مما إذا كان موقعك عرضة للاختراق

أبدأ بقاعدة بسيطة: إذا كان لديك كود مخصص، فلديك نقاط نهاية. وإذا كان لديك نقاط نهاية، فيجب عليك جردها.

تدقيق سريع عبر WP-CLI: ابحث عن الأنماط الخطيرة

على خادم مزود بـ WP-CLI، ابدأ بتحديد موقع إجراءات AJAX العامة وتحديثات الخيارات.

# Rechercher des actions AJAX accessibles aux non-connectés
wp eval 'echo "Mu-plugins:n";' && grep -R --line-number "wp_ajax_nopriv_" wp-content/mu-plugins wp-content/plugins wp-content/themes 2>/dev/null

# Rechercher des endpoints REST custom
grep -R --line-number "register_rest_route" wp-content/mu-plugins wp-content/plugins wp-content/themes 2>/dev/null

# Rechercher des écritures sensibles
grep -R --line-number "update_option|add_option|set_transient|wp_insert_user|wp_update_user" wp-content/mu-plugins wp-content/plugins wp-content/themes 2>/dev/null

ما تبحث عنه:

  • كتابة ردود الاتصال (update_option, wp_insert_user(كتابة الملفات) يمكن الوصول إليها من wp_ajax_nopriv ;
  • مسارات REST مع permission_callback = __return_true (لقد رأيته أثناء الإنتاج، أكثر من مرة)؛
  • عمليات التحقق الضعيفة (على سبيل المثال) sanitize_text_field (يستخدم بدلاً من التحقق من صحة التنسيق).

راجع السجلات: الإشارات النموذجية

في سجلات الوصول (Nginx/Apache)، راقب ما يلي:

  • الصور على /wp-admin/admin-ajax.php بمعايير عمل متكررة؛
  • الطلبات سأعين في /wp-json/ باتجاه مساحات أسماء غير متوقعة؛
  • رموز 401/403 على دفعات (محاولة الوصول)؛
  • وكلاء المستخدم الفارغون أو غير المتناسقين.

مخطط تشخيصي

عرض السبب المحتمل التحقق الحلول
خيارات الموقع التي تتغير "بمفردها" نقطة نهاية AJAX/REST غير محمية، حساب مسؤول مخترق بحث update_option + الإجراءات العامة؛ تحقق من السجلات على admin-ajax.php أضف قيمة عشوائية (nonce) + السعة؛ ثم احذفها. nopriv إعادة تعيين كلمات المرور والمفاتيح
تم إدخال رسائل غير مرغوب فيها في الصفحات/مقالات تم تخزين هجوم XSS عبر خيار/بيانات تعريفية غير مُفلترة، أو حساب ناشر مخترق قارن بين المراجعات، وافحص محتوى HTML؛ وافحص خيارات التحميل التلقائي تنظيف المحتوى؛ تقييد استخدام لغة HTML؛ تشديد الأدوار/الصلاحيات
إعادة التوجيه إلى موقع خارجي خيار siteurl/home إضافة معدلة وخبيثة، تم حقن جافا سكريبت يتحكم home/siteurl في قاعدة البيانات؛ تحقق wp_options استعادة القيم؛ إزالة الباب الخلفي؛ إضافة عناصر التحكم وجدار حماية تطبيقات الويب (WAF)
حمل وحدة المعالجة المركزية admin-ajax.php تم استغلال نقطة نهاية عامة (هجوم حجب الخدمة على التطبيق) أهم عناوين URL (GoAccess)، والسجلات؛ وتحليل الاستعلامات تقييد الإجراءات العامة؛ التخزين المؤقت؛ تحديد معدل الطلبات (الخادم/جدار حماية تطبيقات الويب)

أخطاء شائعة في مجال الأمن

خطأ صعب الحلول
استعمال wp_ajax_nopriv_* من أجل عملية الكتابة تعديل غير موثق، برامج آلية، هجمات تزوير الطلبات عبر المواقع إزالة nopriv أو يقتصر على القراءة؛ يتطلب مصادقة + رمز عشوائي
تحقق من قيمة عشوائية (nonce) ولكن ليس من الإمكانيات. يمكن للحساب الأساسي تنفيذ إجراءات إدارية current_user_can() نظامي لجميع الإجراءات الحساسة
التعقيم "العام" بدلاً من التحقق من الصحة بيانات غير متناسقة، حلول بديلة، أخطاء منطقية التحقق من صحة التنسيق/الطول/القائمة البيضاء + التنظيف المناسب
يمكنك اختيارياً تخزين ملفات HTML/JS وعرضها بدون استخدام علامات الهروب. XSS مخزنة تجنب استخدام لغة HTML المجانية؛ وإلا wp_kses() + esc_html()/esc_attr()
انسخ مقتطفًا من درس تعليمي قديم واجهة برمجة تطبيقات قديمة، ثغرات أمنية، عدم توافق بين ووردبريس 6.9.4 وبي إتش بي 8.1 تحقق من موقع developer.wordpress.org؛ واختبر في وضع التجريب.
ضع الكود في القالب الرئيسي فشل التحديث، موقع ويب معطل إضافة مخصصة أو إضافة متعددة؛ قالب فرعي إذا لزم الأمر
خطأ في الربط (على سبيل المثال، تم تسجيل REST مبكرًا جدًا أو متأخرًا جدًا) المسار غير متاح، الحلول البديلة عبر نظام الرجوع استعمال rest_api_init بالنسبة لـ REST، توجد خطافات مخصصة للمسؤول
نسيان مسح ذاكرة التخزين المؤقت بعد الإصلاح تظن أنك أصلحت المشكلة، لكن جافا سكريبت القديمة لا تزال تعمل مسح ذاكرة التخزين المؤقت للملحقات/شبكة توصيل المحتوى/المتصفح؛ إصدار الأصول
الاختبار على بيئة الإنتاج بدون نسخ احتياطية انقطاع، فقدان البيانات خطة التجهيز + النسخ الاحتياطي + خطة التراجع

قائمة التحقق من التصلب

  • التحديث WordPress 6.9.4+، والقوالب والإضافات (وإزالة تلك التي لم تعد مطلوبة).
  • PHP 8.1 + (يفضل أن يكون الإصدار 8.2/8.3 إذا كانت حزمة البرامج لديك تدعم ذلك) والإضافات المحدثة.
  • تعطيل المحرر : DISALLOW_FILE_EDIT.
  • حظر PHP في عمليات التحميل (ما يعادل Apache/Nginx) وتحقق من أذونات الملفات.
  • فرض HTTPS + FORCE_SSL_ADMIN إذا كان ذلك ينطبق.
  • نقاط نهاية المخزون : مسارات REST، إجراءات AJAX، خطافات الويب الواردة.
  • لجميع أنواع الكتابة : nonce + capacity + strict validation + logs.
  • قلل عدد الأدوار : لا يوجد مسؤول مشترك، حسابات مُسماة، تفعيل المصادقة الثنائية إن أمكن.
  • النسخ الاحتياطي المهام اليومية، واختبارات الترميم، والتخزين خارج الموقع.
  • سجل : سجلات الخادم + سجلات التطبيق للإجراءات الحساسة.

ماذا لو كان الموقع مخترقاً بالفعل؟

إذا كنت تشك في وجود اختراق، فإن النهج الخاطئ هو "مجرد تغيير كلمة مرور المسؤول". إذا كان هناك باب خلفي، فسوف يعيد إنشاء الوصول.

  1. ضع الموقع في وضع الصيانة (أو على الأقل حظر المسؤول) حتى تستقر الأمور. إذا كان لديك شبكة توصيل محتوى/جدار حماية تطبيقات الويب، فقم بتفعيل وضع الحماية المحسّن.
  2. أنشئ نسخة احتياطية جنائية (الملفات + قاعدة البيانات) قبل التنظيف. ستحتاج إلى ذلك لفهم المدخلات وإثبات ما تغير.
  3. حدد نقطة الدخول :
    • الإضافات المضافة/المحدثة مؤخراً؛
    • مقتطفات في ملف functions.php / إضافة المقتطفات؛
    • حسابات إدارية غير معروفة؛
    • مسارات REST/AJAX مخصصة بدون permission_callback/nonce.
  4. أعد تثبيت نظام ووردبريس الأساسي بشكل صحيح (استبدال) wp-admin et wp-includes (من مصدر رسمي)، دون استبدال wp-content حاليا.
  5. تنظيف محتوى ووردبريس :
    • إزالة القوالب/الإضافات غير المعروفة؛
    • أعد التثبيت من wordpress.org/plugins المكونات الإضافية اللازمة؛
    • ابحث عن أحدث ملفات PHP في uploads.
  6. قم بمراجعة قاعدة البيانات :
    • حسابات المسؤولين؛
    • خيارات مشبوهة (تحميل تلقائي ضخم، نصوص برمجية)؛
    • المحتوى المُضاف (المقالات، والأدوات، والقوالب).
  7. إعادة ضبط جميع الأسرار :
    • كلمات المرور (WP، FTP/SSH، قاعدة البيانات، الاستضافة)؛
    • مفاتيح أمان ووردبريس (AUTH_KEY، إلخ.) ؛
    • رموز واجهة برمجة التطبيقات (SMTP، CDN، الدفع، reCAPTCHA).
  8. تطبيق الضوابط : جدار حماية تطبيقات الويب، المصادقة الثنائية، تحديد عدد المحاولات، تنبيهات إنشاء المسؤول.
  9. تحقق من التسليم : مسح ذاكرة التخزين المؤقت، وفحص الواجهة الأمامية (مصدر HTML) بحثًا عن البرامج النصية المحقونة، وإعادة اختبار المسارات الحرجة (تسجيل الدخول، والنماذج، والدفع).

نصيحة مفيدة: إذا كان لديك WP-CLI، فقم بإدراج المسؤولين وابحث عن الحسابات الحديثة.

wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

نصائح الصيانة والتوافق

في ووردبريس 6.9.4، يوفر النظام الأساسي أساسًا متينًا، لكن أمانك يعتمد على انضباطك في التطوير.

يفضل استخدام إضافة (أو إضافة mu) لرمز الأمان.

وضع نقاط نهاية REST/AJAX في قالب (حتى لو كان قالبًا فرعيًا) فكرة سيئة. كثيرًا ما رأيتُ إعادة تصميم باستخدام Divi/Elementor تُعطّل تحديثًا أمنيًا بسبب تغيير القالب. إضافة صغيرة للموقع أكثر استقرارًا وقابلية للتحديث.

الأداء: احذر من خيارات التحميل التلقائي

يتم تحميل كل خيار من خيارات التحميل التلقائي في معظم الطلبات. إذا قمت بتخزين البيانات (JSON، HTML، قوائم)، فإنك تزيد من حجم الملف. alloptionsفي مواقع Avada التي تحتوي على العديد من الخيارات، يمكن أن يصبح هذا الأمر عائقاً.

تحسين محركات البحث: التنازلات تترك آثاراً

بعد التنظيف، راقب ما يلي:

  • وحدة تحكم البحث (صفحات البريد العشوائي، عمليات إعادة التوجيه)؛
  • تم إنشاء خرائط الموقع؛
  • روابط خارجية مُضافة؛
  • وقت الاستجابة (البرامج الضارة = وحدة المعالجة المركزية).

التوافق المستقبلي

تجنب استخدام الأجزاء البرمجية التي تعتمد على تطبيقات داخلية. التزم بواجهات برمجة التطبيقات الموثقة: واجهة برمجة تطبيقات REST، الإعدادات واجهة برمجة التطبيقات (API)، خيارات واجهة برمجة التطبيقات. عند ترحيل كود AJAX القديم إلى REST، اسمح بفترة انتقالية ولكن قم بإزالة نقطة النهاية القديمة في أسرع وقت ممكن.


الموارد

الأسئلة الشائعة

هل يجب عليّ التخلي عن ملف admin-ajax.php؟

لا. بالنسبة لإجراءات الإدارة الداخلية البسيطة، wp_ajax_* لا يزال هذا صحيحًا. ولكن بالنسبة لنقاط النهاية المنظمة والقابلة للصيانة، فإن واجهة برمجة تطبيقات REST تُعدّ أنظف بشكل عام. النقطة التي لا تقبل المساومة: nonce + capacity لأي فعل كتابي.

هل يُعدّ رمز التحقق (nonce) في ووردبريس كافياً لتأمين إجراء ما؟

لا. يقتصر دور رمز التحقق (nonce) بشكل أساسي على الحد من هجمات تزوير الطلبات عبر المواقع (CSRF). فهو لا يحل محل التحكم في سعة التخزين. في حوادث واقعية، رأيت رموز التحقق مُطبقة بشكل صحيح... ولكنها متاحة لأدوار ذات مستوى وصول منخفض للغاية عبر صفحة واجهة المستخدم.

لماذا يتم التحقق من طول النص إذا كنت قد قمت بتنظيفه بالفعل؟

لأنّ عملية التنظيف لا تُطبّق قواعد عملك ولا تحمي من البيانات الضخمة. يُساهم التحقق من طول البيانات في منع إساءة الاستخدام (التخزين، والسجلات، والأداء) والسلوك غير المتوقع.

أين يجب وضع هذا الكود: في ملف functions.php، أو في إضافة snippets، أو في إضافة مخصصة؟

لأسباب تتعلق بالسلامة، تجنب functions.php من القالب الرئيسي. واحد المكونات الإضافية المخصصة (أو mu-plugin) أكثر موثوقية وقابلية للتحديث، ولا يختفي عند تغيير السمات (Divi/Elementor/Avada).

أواجه خطأ 403 في مسار REST بعد إضافة قيمة nonce. هل هذا طبيعي؟

غالباً نعم: قد يكون السبب هو فقدان أو انتهاء صلاحية رمز التحقق (nonce)، أو عدم إرسال ملفات تعريف الارتباط، أو وجود اتصال بين نطاقين. تأكد من أنك ترسل X-WP-Nonceأن المستخدم متصل بشكل صحيح، وأن المكالمة تستهدف نفس النطاق (احذر من البيئات التي تحتوي على www/non-www).

كيف يمكنني منع ذاكرة التخزين المؤقت من إفساد اختبارات الأمان الخاصة بي؟

قم بإصدار أصولك (إعدادات الإصدار في wp_enqueue_scriptقم بمسح ذاكرة التخزين المؤقت للملحق/شبكة توصيل المحتوى، واختبر في وضع التصفح الخاص. لقد رأيتُ في كثير من الأحيان حلولاً "غير فعّالة" كانت مجرد مسح لذاكرة التخزين المؤقت.

هل يمنع خيار DISALLOW_FILE_EDIT المتسلل؟

يمنع هذا الإجراء تقنية شائعة (تعديل القوالب/الإضافات من لوحة التحكم). إذا كان المهاجم يمتلك بالفعل صلاحيات الوصول عبر بروتوكول نقل الملفات (FTP) أو بروتوكول SSH أو إمكانية تنفيذ التعليمات البرمجية عن بُعد (RCE)، فلن يكون ذلك كافيًا. ولكن في سيناريو دفاعي متعدد الطبقات، يُعد هذا إعدادًا بسيطًا ومفيدًا.

كيفية التعرف بسرعة على ثغرات XSS المخزنة عبر الخيارات؟

انتبه لخيارات التحميل التلقائي الكبيرة، وابحث عن الأجزاء. <script, onerror=, javascript: في قاعدة البيانات. ثم، صحح الأمر من المصدر: من يمكنه كتابة هذه الخيارات، وكيف يتم عرضها (مع مراعاة الهروب)؟

ما هو الحد الأدنى من المتطلبات لنقطة نهاية تقوم بتعديل قاعدة البيانات؟

المصادقة (المستخدم المسجل دخوله)، والتفويض (القدرة)، والرقم العشوائي (المضاد لهجمات CSRF)، والتحقق الصارم من صحة المعلمات، وتسجيل الإجراءات الحساسة (على الأقل في وضع التصحيح/التجريب).

يُتيح الملحق الخاص بي، والذي يعمل مع طرف ثالث، مسار REST عامًا. هل يجب أن أقلق؟

ليس بالضرورة. قد يكون الطريق العام الظاهر للعيان أمرًا طبيعيًا. أما الطريق الخطير فهو الطريق العام الذي مكتوب أو التي تكشف بيانات حساسة. التدقيق permission_callback والأساليب المسموح بها (POST/PUT/DELETE).