لقد أصبحت حتى الآن على دراية بأساسيات تطوير الإضافات والقوالب في ووردبريس. والآن سيكون الوقت مناسبًا أيضًا للنظر في الآثار الأمنية لكتابة التعليمات البرمجية.
في هذا الدرس، ستتعلم كيفية التطوير مع مراعاة الأمان.
ستتعلم فوائد ضمان أمان التعليمات البرمجية، والخطوات التي يجب اتباعها لتأمينها، وأين تجد مزيدًا من المعلومات حول التطوير مع مراعاة الأمان.
إخلاء المسؤولية
أُنشئ هذا الدرس كمقدمة للتطوير مع مراعاة الأمان عند تطوير الإضافات والقوالب. التعليمات البرمجية المستخدمة في هذا الدرس مبسطة جدًا. يجب ألا تستخدم أيًا من التعليمات البرمجية المستخدمة في هذا البرنامج التعليمي في إضافاتك أو قوالبك.
يرجى قراءة الوثائق الكاملة حول الأمان في https://developer.wordpress.org/apis/security/ في دليل مطوري ووردبريس، للتأكد من اتباعك الأساليب والإجراءات الصحيحة.
ما المقصود بالتطوير مع مراعاة الأمان؟
التطوير مع مراعاة الأمان هو عملية ضمان أن التعليمات البرمجية لا تعمل فحسب، بل لا تؤدي أيضًا إلى إدخال أي ثغرات أمنية.
إذا كانت التعليمات البرمجية للإضافة أو القالب تحتوي على ثغرات أمنية، فقد تجعل أي موقع ووردبريس ثبّت منتجك مفتوحًا أمام هجمات محتملة، وقد تؤدي إلى اختراق ذلك الموقع.
عند كتابة التعليمات البرمجية، من المهم تطوير عقلية أمنية والتفكير في كيفية إساءة استخدام التعليمات البرمجية الخاصة بك.
- لا تثق بأي بيانات، سواء كانت إدخالًا من المستخدم أو بيانات من واجهة برمجة تطبيقات تابعة لجهة خارجية أو حتى بيانات في قاعدة بياناتك. احرص دائمًا على التحقق من صلاحيتها وأمان استخدامها.
- يحتوي ووردبريس على عدد من واجهات برمجة التطبيقات التي يمكن أن تساعدك في المهام الشائعة، مثل تنقية إدخال المستخدم والتحقق من صحة البيانات وتهريب المخرجات. اعتمد على استخدام هذه الواجهات للمساعدة في التحقق من صحة بياناتك وتنقيتها بدلًا من كتابة دوالك الخاصة.
- واكب الثغرات الشائعة واحرص على تحديث التعليمات البرمجية لمنعها.
أين يندرج الأمان ضمن عملية التطوير؟
ينبغي أن يكون الأمان محل اعتبار في كل مرحلة من مراحل عملية التطوير.
بوجه عام، يحدث أكبر عدد من الثغرات الأمنية التي يتم العثور عليها في طبقة PHP، التي تُنفذ على الخادم.
لذلك، سيركز هذا الدرس على أهم التدابير الوقائية الشائعة في تعليمات PHP البرمجية الخاصة بك.
تنقية المدخلات
تتمثل إحدى الخطوات الأولى عند التطوير في ضمان تنقية أي إدخال من المستخدم. وهذا يعني التحقق من أي بيانات يتم تمريرها من المستخدم، مثل إرسال نموذج أو معلمة في عنوان URL، للتأكد من أمان استخدامها.
في هذا المثال، يجري إرسال حقلي الاسم والبريد الإلكتروني من نموذج تُنشئه إضافة، ثم حفظهما في جدول قاعدة بيانات مخصص يُسمى form_submissions؛
$name = $_POST['name'];
$email = $_POST['email'];
global $wpdb;
$table_name = $wpdb->prefix . 'form_submissions';
$sql = "INSERT INTO $table_name (name, email) VALUES ('$name', '$email')";
$result = $wpdb->query($sql);
كما ترى، يجري حفظ البيانات مباشرةً في قاعدة البيانات من دون أي تنقية.
هذا يعني أنه إذا أرسل أحد المستخدمين اسمًا مثل John'; DROP TABLE form_submissions;-- فسيتم تنفيذ استعلام SQL INSERT، يليه استعلام DROP، وسيُحذف الجدول من قاعدة البيانات!
يحتوي ووردبريس على واجهة برمجة تطبيقات للتنقية يمكن استخدامها لتنقية البيانات الواردة. يمكنك استخدام الدالتين sanitize_text_field وsanitize_email لتنقية حقلي الاسم والبريد الإلكتروني قبل استخدامهما في الاستعلام.
$name = sanitize_text_field( $_POST['name'] );
$email = sanitize_email( $_POST['email'] );
global $wpdb;
$table_name = $wpdb->prefix . 'form_submissions';
$sql = "INSERT INTO $table_name (name, email) VALUES ('$name', '$email')";
$result = $wpdb->query($sql);
لاحظ أن التعليمات البرمجية تتبع مبدأً أساسيًا لتنقية البيانات، وهو القيام بذلك في أقرب وقت ممكن.
لمزيد من القراءة حول دوال التنقية المتاحة لمطوري ووردبريس، راجع صفحة تنقية البيانات في وثائق مطوري ووردبريس.
التحقق من صحة البيانات (4:06)
التحقق من صحة البيانات هو عملية اختبارها مقابل نمط محدد مسبقًا (أو أنماط محددة مسبقًا) مع نتيجة حاسمة، إما صالحة أو غير صالحة.
يمكن أن تأتي البيانات غير الموثوقة من مصادر عديدة، مثل المستخدمين وبيانات واجهات برمجة التطبيقات التابعة لجهات خارجية، وحتى بيانات قاعدة البيانات الخاصة بك يمكن اعتبارها غير موثوقة، خاصةً إذا عدّلها شيء آخر. حتى مسؤولو الموقع قد يخطئون ويدخلون بيانات غير صحيحة أو غير آمنة، لذا من المهم التحقق من بياناتك دائمًا.
في هذا المثال، تتطلب دالة الحذف إرسال معرّف رقمي إلى استدعاء admin-ajax:
add_action( 'wp_ajax_delete_form_submission', 'wp_learn_delete_form_submission' );
function wp_learn_delete_form_submission() {
if ( ! isset( $_POST['id'] ) ) {
wp_send_json_error( 'Invalid ID' );
}
$id = $_POST['id'];
global $wpdb;
$table_name = $wpdb->prefix . 'form_submissions';
$sql = "DELETE FROM $table_name WHERE id = $id";
$result = $wpdb->get_results( $sql );
return wp_send_json( array( 'result' => $result ) );
}
هنا يُستخدم المعرّف مباشرةً في استعلام SQL من دون أي تحقق من صحته. ومرة أخرى، هذا يعني أنه إذا أرسل أحد المستخدمين معرّفًا مثل 1; DROP TABLE form_submissions; فسيتم تنفيذ استعلام SQL DROP نفسه بعد الحذف، وسيُحذف الجدول.
لمنع ذلك، يمكنك استخدام وظيفة تحويل الأنواع في PHP، لضمان أن تكون قيمة $id دائمًا قيمة صحيحة. ويمكن إجراء ذلك بإضافة (int) قبل اسم المتغير، كما يلي:
$id = (int) $_POST['id'];
لاحظ أن هذا لن يعمل إلا إذا كان من الممكن تحويل الحرف الأول في السلسلة الممررة عبر مصفوفة $_POST إلى عدد صحيح؛ وإلا فستكون قيمة $id هي 0. في هذه الحالة، من الجيد تحديث التعليمات البرمجية لمعالجة هذه الحالة.
تتبع التعليمات البرمجية أيضًا مبدأً أساسيًا للتحقق من صحة البيانات، وهو القيام بذلك في أقرب وقت ممكن.
if ($id === 0){
// return early with an error
return wp_send_json( array( 'result' => 'Invalid ID passed' ) );
}
لمزيد من القراءة حول الطرق المختلفة للتحقق من صحة البيانات، راجع قسم التحقق من صحة البيانات في وثائق مطوري ووردبريس.
تهريب المخرجات
من الجوانب الأخرى للأمان ضمان أمان أي معلومات تعرضها على المتصفح، بما في ذلك أي نص أو HTML أو تعليمات JavaScript برمجية أو بيانات من قاعدة البيانات.
حتى إذا لم تكن تعليماتك البرمجية مسؤولة عن مصدر البيانات المعروضة، فهي مسؤولة عن عرضها بأمان.
في هذا المثال، تجلب التعليمات البرمجية عمليات إرسال النماذج من قاعدة البيانات، ثم تمر عبر عمليات الإرسال وتعرض بيانات الإرسال في شاشة الإدارة في لوحة تحكم ووردبريس:
$submissions = wp_learn_get_form_submissions();
?>
<div class="wrap" id="wp_learn_admin">
<h1>Admin</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<?php foreach ($submissions as $submission){ ?>
<tr>
<td><?php echo $submission->name; ?></td>
<td><?php echo $submission->email; ?></td>
<td><a class="delete-submission" data-id="<?php echo $submission->id?>" style="cursor:pointer;">Delete</a></td>
</tr>
<?php } ?>
</table>
</div>
<?php
لدينا هنا ثلاث قطع من البيانات التي تحتاج إلى تهريب، وهي حقلا $submission->name و$submission->email، بالإضافة إلى $submission->id.
<td><a class="delete-submission" data-id="<?php echo (int) $submission->id?>" style="cursor:pointer;">Delete</a></td>
بالنسبة إلى حقلي الاسم والبريد الإلكتروني، يمكننا استخدام دالة التهريب المضمنة في ووردبريس esc_html(). ويمكن تهريب المعرّف بتحويله إلى عدد صحيح، كما قد تفعل عند التحقق من صحة البيانات.
<td><?php echo esc_html( $submission->name ); ?></td>
<td><?php echo esc_html( $submission->email ); ?></td>
<td><a class="delete-submission" data-id="<?php echo (int) $submission->id?>" style="cursor:pointer;">Delete</a></td>
لاحظ أن هذه التعليمات البرمجية تتبع مبدأً أساسيًا لتهريب البيانات، وهو تهريب البيانات في وقت متأخر قدر الإمكان.
لمزيد من القراءة حول الطرق المختلفة لتهريب المخرجات، راجع قسم تهريب البيانات في وثائق مطوري ووردبريس.
منع الطلبات غير الصالحة
عند إجراء أي طلب، من المهم التحقق من صلاحية الطلب. وهذا يعني التحقق من أن الطلب صادر من مصدر موثوق.
على سبيل المثال، قد يكون لديك رمز قصير يعرض نموذجًا يمكن للمستخدمين إرسال معلوماتهم من خلاله.
قد تبدو الدالة التي تعرض النموذج على النحو التالي.
add_shortcode( 'wp_learn_form_shortcode', 'wp_learn_form_shortcode' );
function wp_learn_form_shortcode() {
ob_start();
?>
<form method="post">
<input type="hidden" name="wp_learn_form" value="submit">
<div>
<label for="email">Name</label>
<input type="text" id="name" name="name" placeholder="Name">
</div>
<div>
<label for="email">Email address</label>
<input type="text" id="email" name="email" placeholder="Email address">
</div>
<div>
<input type="submit" id="submit" name="submit" value="Submit">
</div>
</form>
<?php
$form = ob_get_clean();
return $form;
}
?>
عندما يرسل المستخدم النموذج، تُرسل البيانات إلى الخادم. ثم تتم معالجة البيانات وتنقيتها وتخزينها في قاعدة البيانات.
add_action( 'wp', 'wp_learn_maybe_process_form' );
function wp_learn_maybe_process_form() {
if (!isset($_POST['wp_learn_form'])){
return;
}
$name = sanitize_text_field( $_POST['name'] );
$email = sanitize_email( $_POST['email'] );
global $wpdb;
$table_name = $wpdb->prefix . 'form_submissions';
$sql = "INSERT INTO $table_name (name, email) VALUES ('$name', '$email')";
$result = $wpdb->query($sql);
if ( 0 < $result ) {
wp_redirect( WPLEARN_SUCCESS_PAGE_SLUG );
die();
}
wp_redirect( WPLEARN_ERROR_PAGE_SLUG );
die();
}
لأن النموذج قد يظهر في أي صفحة يُستخدم فيها الرمز القصير، فمن المحتمل أن يحاول مستخدم ضار إرسال طلب POST إلى النموذج، إما بحثًا عن ثغرة في الإضافة، أو بإرسال طلبات متعددة إلى النموذج.
لمنع ذلك، يمكنك التحقق من أن الطلب صادر من مصدر موثوق. وللقيام بذلك، يمكنك تنفيذ ما يُسمى nonce، أو رقم يُستخدم مرة واحدة.
أولًا، في النموذج نفسه، يمكنك إضافة حقل nonce باستخدام الدالة wp_nonce_field، وتمرير إجراء nonce واسم nonce إلى الدالة:
wp_nonce_field( 'wp_learn_form_nonce_action', 'wp_learn_form_nonce_field' );
عند عرض النموذج في الواجهة الأمامية، يُضاف حقل مخفي إلى النموذج، باستخدام اسم nonce باعتباره السمتين id وname للحقل المخفي، وnonce المُنشأ باعتباره قيمة الحقل. تُرسل هذه البيانات عند إرسال النموذج.
بعد ذلك، في الدالة التي تعالج بيانات النموذج، يمكنك التحقق من صلاحية nonce باستخدام الدالة wp_verify_nonce، وذلك بتمرير حقل nonce المُرسل عبر POST وإجراء nonce إلى هذه الدالة. إذا كانت نتيجة هذا التحقق هي false، يمكنك الخروج مبكرًا، مما يمنع تنفيذ أي تعليمات برمجية أخرى.
if ( ! wp_verify_nonce( $_POST['wp_learn_form_nonce_field'], 'wp_learn_form_nonce_action' ) {
wp_redirect( WPLEARN_ERROR_PAGE_SLUG );
die();
}
في كل مرة تُجري فيها تعليماتك البرمجية طلب ويب، سواء كان ذلك عبر إعادة التوجيه إلى عنوان URL جديد أو إرسال بيانات POST إلى نموذج أو إجراء طلب AJAX، ينبغي أن تتحقق من صلاحية الطلب.
لمزيد من القراءة حول كيفية استخدام nonces في إضافاتك، راجع قسم Nonces في وثائق مطوري ووردبريس.
منع المستخدمين غير المصادق عليهم
اعتمادًا على وظائف التعليمات البرمجية الخاصة بك، من الجيد تقييد ميزات معينة على المستخدمين الذين لديهم مستوى صلاحيات محدد فقط. على سبيل المثال، قد تكون لديك دالة تحذف البيانات من قاعدة البيانات.
function wp_learn_delete_form_submission() {
if ( ! isset( $_POST['id'] ) ) {
wp_send_json_error( 'Invalid ID' );
}
$id = (int) $_POST['id'];
global $wpdb;
$table_name = $wpdb->prefix . 'form_submissions';
$sql = "DELETE FROM $table_name WHERE id = $id";
$result = $wpdb->get_results( $sql );
return wp_send_json( array( 'result' => $result ) );
}
مع أنك قد تبذل قصارى جهدك لمنع أي شخص لا يملك الصلاحية من تشغيل هذه الدالة، فلا يزال من الجيد تضمين عمليات تحقق من هذه الحالة.
يتضمن ووردبريس نظامًا قويًا لـ أدوار المستخدمين وصلاحياتهم، يتيح لك استخدام أدوار المستخدمين وصلاحياتهم الافتراضية أو إنشاء أدوار وصلاحيات مخصصة.
في هذه الحالة، قد يكون الأمر بسيطًا مثل السماح فقط للمستخدمين الذين يملكون صلاحية إدارة خيارات الموقع، وهي صلاحية قياسية مضمنة في دور المسؤول.
function wp_learn_delete_form_submission() {
if ( ! current_user_can( 'manage_options' ) ) {
return wp_send_json( array( 'result' => 'Authentication error' ) );
}
// rest of function code
}
تحتوي وثائق مطوري ووردبريس على قسم مفصل حول أدوار المستخدمين وصلاحياتهم، يتضمن قائمة بالصلاحيات الافتراضية وكيفية إنشاء صلاحيات مخصصة.
قراءات إضافية
لتهيئة نفسك للتفكير في التطوير مع مراعاة الأمان، احرص على قراءة المدخل الخاص بـالأمان في وثائق مطوري ووردبريس، إذ يتضمن جميع الأمثلة الواردة في هذا الدرس، بالإضافة إلى معلومات إضافية حول أفضل ممارسات الأمان والثغرات الشائعة والمزيد من أمثلة التعليمات البرمجية.