نانس (Nonce) در وردپرس چیه و چجوری ازش استفاده کنیم؟

نانس چیه؟
نانس چیه؟

در مهندسی امنیت، نانس عبارت است از تعدادی عدد دلخواه که تنها یکبار برای امضای یک ارتباط استفاده می‌شود.

پاراگراف بالا توضیح خلاصه ویکیپدیا از نانسه. کلمه Nonce در اصل از ترکیب کلمات یک جمله تولید شده که تو رفرنس‌های مختلف جمله‌ی که تشکیل‌دهنده رو چیزای مختلفی می‌گن:

  • Number Once
  • Number Used Once
  • Number Only Used Once

همونطور که می‌بینید مفهوم این جملات یکیه و دارن میگن «عددی که فقط یکبار استفاده میشه».

کاربرد نانس چیه؟

نانس یه توکن یکتاست که برای اضافه کردن یک لایه امنیتی به اپلیکیشن استفاده میشه. کسایی که با مفهوم بلاکچین و ماینینگ آشنا باشن احتمالا نانس به گوششون خورده. امنیت بلاکچین رو نانس تامین میکنه.

نمونه کارکرد نانس
نمونه کارکرد نانس


عکس بالا یه مثال خوبه که بهتر متوجه بشین. پروسه فعالیت یک نانس اینجوری میشه:

  1. سرور یک نانس تولید میکنه، اون رو لوکالی ذخیره میکنه و به کلاینت میفرستتش.
  2. کلاینت کارشو انجام میده و درخواستشو به همراه نانسی که بهش داده شده به سمت سرور میفرسته.
  3. سرور که درخواست رو دریافت میکنه اول چک میکنه ببینه آیا تو درخواست نانس وجود داره یا نه، اگه وجود داشت مقدار نانس رو با مقداری که لوکالی ذخیره کرده بود با مقایسه اعتبارسنجی میکنه و اگه معتبر بود درخواست رو سالم و قابل اعتماد تلقی میکنه و کار رو انجام میده.
  4. بعد از اینکه اعتبارسنجی انجام شد نانسی که ازش استفاده شده باید نامعتبر یا نابود بشه تا مفهوم Number Used Only Once (عددی که فقط یکبار استفاده میشه) محقق بشه.

نانس در وردپرس یه نانس واقعی نیست!

شاید بدونین که وردپرس خودش یه سیستم نانس داره. اما این سیستم وردپرس نانس واقعی نیست و مفهوم Number Used Only Once (عددی که فقط یکبار استفاده میشه) رو محقق نمیکنه. چرا؟ چون مرحله ۴ام از پروسه‌ای که بالاتر نوشتم رو رعایت نمیکنه و میتونه بیشتر از یک بار استفاده بشه.

وردپرس نانسی که می‌سازه رو حداقل ۱۲ ساعت معتبر نگه می‌داره (البته میتونه تا ۲۴ ساعت هم معتبر بمونه، بستگی به تیکش داره). در نتیجه میشه از یه نانس بی‌شمار مرتبه استفاده کرد و این مفهوم اصلی نانس رو نقض می‌کنه.

تیک-تیک

تیک‌ها یا Ticks یکی از پارامتر‌هایی هستن که وردپرس برای ساختن نانس ازشون استفاده می‌کنه که با فانکشن wp_nonce_tick در پروسه ساخته شدن نانس تعریف میشن.

تیک یک مقداریه که در هر نیمه‌روز (۱۲:۰۰:۰۰) و نیمه‌شب (۰۰:۰۰:۰۰) یک واحد تغییر میکنه، یعنی هر ۱۲ ساعت. تیک برای مشخص کردن لایف‌تایم هر نانس استفاده میشه. همونطور که گفتیم لایف‌تایم هر نانس تو وردپرس نهایتا تا ۲۴ ساعته. یا به عبارت درست‌تر، به انداره مقدار تیک حال حاضر و تیک قبلی اعتبار داره.

حالا چون تیک هر ۱۲ ساعت تغییر می‌کنه، تنها در صورتی یه نانس می‌تونه ۲۴ ساعت معتبر بمونه که ساعت ۰۰:۰۰:۰۱ یا ۱۲:۰۰:۰۱ ساخته شده باشه. جدول زیر رو ببینین بهتر متوجه میشین:

لایف‌تایم نانس وردپرس
لایف‌تایم نانس وردپرس

با این وضعیت نانس وردپرس چیکار کنیم؟

درسته که نانس وردپرس نانس واقعی نیست و این از نظر امنیتی کمی ضعیفش میکنه، ولی در هر صورت برای جلوگیری از CSRF خیلی بدرد میخوره. فقط حواستون باشه که فقط روی نانس برای امنیت حساب نکنین و فاکتور‌های امنیتی دیگه‌ هم حتما لحاظ کنین.

در کل یه نانس واقعی هم فقط به شما میگه که سورس رکوئستی که دارین به اصطلاح geniuinعه (اصیله، قابل اعتماده) و کاری با این نداره که اصلا آیا سورسِ رکوئست پرمیشنِ دادنِ این رکوئست رو داره یا نه!

نحوه استفاده از نانس وردپرس

چند تا فانکشن برای ساختن و چند تا فانکشن برای اعتبارسنجی نانس وجود داره که همه رو بررسی میکنیم:

ساختن نانس

وردپرس ۳ تا تابع برای ساختن نانس داره:

تابع wp_create_nonce

wp_create_nonce( string|int $action = -1 )

این تابع برای استفاده کلیه و شما هرجا که نیاز داشته باشین میتونین ازش استفاده کنین تا یه Nonce بسازین. یه ورودی اکشن میگیره که بهتره همیشه ازش استفاده کنین و اکشن رو تعریف کنین تا با یه نانس دیگه کانفلیکت نخوره. مثلا:

// create nonce
$save_form_nonce = wp_create_nonce( 'save_form_' . $form_id );
// usage
<a href=&quotsave.php?action=save_form&nonce_token=<?= esc_attr( $save_form_nonce ); ?>&form=<?= esc_attr( $form_id ); ?>&quot><?php esc_html_e( 'Save', 'textdomain' ); ?></a>

تابع wp_nonce_field

wp_nonce_field( int|string $action = -1, string $name = '_wpnonce', bool $referer = true, bool $echo = true )

این تابع برای توی فرم‌های HTMLعه و خروجیش فیلد مخفی‌ایه که نانس رو به عنوان مقدار داره. چهار تا ورودی میگیره که بهتره همیشه از اولی که اکشنه استفاده کنین و اکشن رو تعریف کنین تا با یه نانس دیگه کانفلیکت نخوره.

ورودی دوم اسم فیلد مخفیه و ورودی چهارم میگه که echo کنم یا نه.

ورودی سوم یک فیلد مخفی اضافه ایجاد میکنه به اسم _wp_http_referer که مقدارش URL رفرریه که از متغیر سوپرگلوبال _SERVER گرفته.

مثلا:

<form method=&quotpost&quot id=&quot80&quot>
   <!-- some form fields -->
   <input type=hidden name=&quotis_edit&quot value=&quot<?php echo esc_attr( $is_edit ); ?>&quot>
   <?php wp_nonce_field( 'save_form_80', 'nonce_token' ); ?>
</form>

تابع wp_nonce_url

wp_nonce_url( string $actionurl, int|string $action = -1, string $name = '_wpnonce' )

این تابع برای URL استفاده میشه که نانس رو به URL به عنوان یه کوئری استرینگ اضافه میکنه. سه تا ورودی میگیره که بهتره همیشه از دومی که اکشنه استفاده کنین و اکشن رو تعریف کنین تا با یه نانس دیگه کانفلیکت نخوره.

ورودی اول URLایه که میخواین نانس رو بهش اضافه کنین و ورودی سوم هم اسم متغیره.

مثلا:

<?php
$url = wp_nonce_url( admin_url(), 'save_form_' . $form_id, 'nonce_token' );
?>
<a href=&quot<?= $url; ?>&quot><?php esc_html_e( 'Save', 'textdomain' ); ?></a>

اعتبارسنجی نانس

وردپرس ۳ تا تابع هم برای اعتبارسنجی نانس داره:

تابع wp_verify_nonce

wp_verify_nonce( string $nonce, string|int $action = -1 )

این تابع مثل تابع اول ساختن نانس برای استفاده کلیه و شما هرجا که نیاز داشته باشین یه نانس رو استفاده کنین میتونین ازش استفاده کنین. ورودی اولش که مقدار خود نانسه و ورودی دومش هم اسم اکشنیه که تو فانکشن ساختن نانس استفاده کردین.

خروجی تابع اگه نانس معتبر نباشه falseعه و اگه معتبر باشه نسبت به این که تو این تیک ساخته شده یا تیک قبلی بین ۱ و ۲ متغیره. اگه تو این تیک ساخته شده باشه ۱ و اگه تو تیک قبلی باشه ۲ برمیگردونه. مثلا:

$nonce = $_REQUEST[ 'nonce_token' ];
$nonce = wp_verify_nonce( $nonce, 'save_form_' . $form_id );
switch ( $nonce ) {
    case 1:
        echo 'Nonce was generated in the current tick';
        break;
    case 2:
        echo 'Nonce was generated in the previous tick';
        break;
    default:
        exit( 'Nonce is invalid' );
}

تابع check_admin_referer

check_admin_referer( int|string $action = -1, string $query_arg = '_wpnonce' )

برخلاف اسم غلط‌اندازش، این فانکشن با پرمیشن‌های یوزر کاری نداره و دقیقا مثل فانکشن قبلیه. تنها تفاوتی که دارن اینه که این فانکشن در صورتی که نانس نامعتبر باشه، به صورت خودکار با صدا زدن فانکشن wp_nonce_ays که متن ?Are you sure رو نمایش میده، اسکریپت رو متوقف میکنه (die). مثلا:

$nonce = $_REQUEST[ 'nonce_token' ];
if ( check_admin_referer( $nonce, 'save_form_' . $form_id ) ) {
  // Nonce validated.
}

تابع check_ajax_referer

check_ajax_referer( int|string $action = -1, false|string $query_arg = false, bool $die = true )

آخرین تابع اعتبارسنجی یه نانس برای رکوئست‌های ایجکس استفاده میشه. این فانکشن ۳ تا ورودی می‌گیره که اولی اکشنه، دومی اسم متغیر در کوئریه و سومی هم میگه بمیرم یا نمیرم. :)

مثلا:

// Ajax Request
<?php
//Create your nonce
$my_ajax_nonce = wp_create_nonce( 'save_form_' . $form_id );
?>

<script type=&quottext/javascript&quot>
jQuery(document).ready(function($){
    var data = {
        action: 'save_form',
        form: '<?php echo $form_id; ?>',
        nonce_token: '<?php echo $my_ajax_nonce; ?>',
    };
    $.post(
           ajaxurl, 
           data,
           function(response) {
           console.log({response});
    });
});


// Ajax Request callback
add_action( 'wp_ajax_save_form', 'save_form' );

function save_form() {
  if ( check_ajax_referer( 'save_form_' . $_post['form'], 'nonce_token' ) ) {
   // Nonce validated.
   wp_send_json_success();
  }
}

اگه نانس واقعی بخوایم چی؟

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

https://github.com/josephyas/wp-real-nonce

اگه سؤال یا نظری داشتین روی لینکدین یا توییتر سریعتر جواب میدم تا اینجا.

منابع: