در وردپرس، REST API به کانال اصلی ارتباط بین بک‌اند و فرانت‌اند تبدیل شده است، اما بدون احراز هویت درست، هر Endpoint به یک سطح حمله باز تبدیل می‌شود و داده سایت در معرض خطر جدی قرار می‌گیرد. تفاوت Application Password، OAuth، Basic Auth، Cookie و Nonce در سناریوهای مختلف، تصمیم‌های معماری را به تصمیم‌های امنیتی گره می‌زند و انتخاب اشتباه، هم امنیت و هم تجربه کاربری را قربانی می‌کند. بدون HTTPS، حتی قوی‌ترین روش احراز هویت هم بی‌اثر است و توکن‌ها در مسیر شنود می‌شوند. مدیریت Capability در سطح REST باید صریح و مبتنی بر نقش باشد و بدون آن، کاربر با کمترین دسترسی می‌تواند به داده حساس برسد. تست احراز هویت REST در سه سطح محلی، Staging و تولید انجام می‌شود و بدون آن، انتشار به تولید ریسک بالایی دارد. در این راهنما از ساختار پایه تا استقرار تولیدی احراز هویت REST را با نگاه مهندسی و کد عملی پوشش می‌دهیم.

در پروژه‌های واقعی، اولین بار که یک Endpoint REST را بدون احراز هویت منتشر می‌کنم، در لاگ سرور می‌بینم که در چند ساعت صدها درخواست مشکوک به آن رسیده است. این راهنما از همان نقطه‌ای شروع می‌کند که تجربه می‌گوید بیشترین ارزش را دارد.

احراز هویت REST API چیست و چرا ضروری است؟

احراز هویت REST API یعنی مشخص کردن این که چه کسی درخواست را ارسال می‌کند و آیا مجاز به انجام این عمل است یا خیر. بدون این دو مرحله، هر کلاینت خارجی می‌تواند داده بخواند یا بنویسد.

پیش از ادامه، راهنمای ساخت API اختصاصی در وردپرس را مطالعه کنید. اگر با REST API وردپرس آشنایی ندارید، راهنمای REST API در وردپرس نقطه شروع مناسبی است.

نشانه‌هایی که احراز هویت REST ضعیف است

اگر Endpoint شما بدون Header Authorization پاسخ می‌دهد، اگر permission_callback شما return true است، یا اگر داده حساس را از Endpoint عمومی می‌خوانید، احراز هویت ضعیف است.

HTTPS و پیش‌نیاز امنیتی

بدون HTTPS، هیچ روش احراز هویتی امن نیست. توکن، رمز عبور و حتی Basic Auth در مسیر شبکه قابل شنود هستند.

# بررسی HTTPS
curl -I https://example.com/wp-json/

# پاسخ مورد انتظار
HTTP/2 200
strict-transport-security: max-age=31536000; includeSubDomains

توصیه می‌کنم HSTS را فعال کنید. راهنمای HSTS در وردپرس نقطه شروع مناسبی است.

TLS و تنظیمات پیشرفته

حداقل TLS 1.2 توصیه می‌شود. برای پروژه‌های حساس، TLS 1.3 انتخاب درستی است. راهنمای تنظیم TLS بدون افزایش تأخیر را ببینید.

Application Password در وردپرس

Application Password روش رسمی و استاندارد وردپرس برای احراز هویت REST API است. این روش از نسخه ۵.۶ در هسته اضافه شد و جایگزین Pluginهای قدیمی مانند Application Passwords شد.

Authorization: Basic base64(username:xxxx xxxx xxxx xxxx xxxx xxxx)

Application Password یک رمز ۲۴ کاراکتری است که به‌صورت گروه‌های چهارتایی نمایش داده می‌شود و در پروفایل کاربر قابل ایجاد و لغو است.

ایجاد Application Password در کد

<?php
$user_id = 5;
$app_name = "WordPressKar Mobile App";

$result = WP_Application_Passwords::create_new_application_password(
    $user_id,
    array( "name" => $app_name )
);

if ( is_wp_error( $result ) ) {
    error_log( $result->get_error_message() );
    return;
}

$password = $result[0];
// این رمز فقط یک بار نمایش داده می‌شود و باید ذخیره شود.

برای مطالعه بیشتر، راهنمای Application Password در وردپرس را ببینید.

محدودسازی Application Password

add_filter( "wp_is_application_passwords_available", function( $available ) {
    return is_ssl();
} );

این فیلتر تضمین می‌کند Application Password فقط روی HTTPS فعال است.

Basic Auth و کاربردهای محدود

Basic Auth روش ساده‌ای است که نام کاربری و رمز را به‌صورت base64 در Header می‌فرستد. این روش فقط در محیط‌های توسعه یا با API Key استفاده می‌شود.

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

اشتباه رایج، استفاده از Basic Auth با رمز عبور اصلی کاربر در تولید است. هرگز این کار را نکنید.

Basic Auth با API Key

<?php
add_filter( "determine_current_user", function( $user_id ) {
    if ( $user_id ) {
        return $user_id;
    }

    $auth = isset( $_SERVER["HTTP_AUTHORIZATION"] ) ? $_SERVER["HTTP_AUTHORIZATION"] : "";
    if ( 0 !== strpos( $auth, "Basic " ) ) {
        return $user_id;
    }

    $decoded = base64_decode( substr( $auth, 6 ) );
    list( $key, $secret ) = array_pad( explode( ":", $decoded, 2 ), 2, "" );

    $stored = get_option( "wpk_api_keys" );
    if ( ! isset( $stored[ $key ] ) || ! hash_equals( $stored[ $key ], $secret ) ) {
        return $user_id;
    }

    return 5;
} );

در پنل مدیریت وردپرس، احراز هویت از طریق Cookie انجام می‌شود. برای REST API، باید Nonce در Header X-WP-Nonce ارسال شود.

fetch( "/wp-json/wp/v2/posts", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-WP-Nonce":   wpApiSettings.nonce,
    },
    credentials: "same-origin",
    body: JSON.stringify( { title: "عنوان جدید" } ),
} );

Nonce در سمت سرور با wp_verify_nonce() اعتبارسنجی می‌شود. راهنمای تابع wp_verify_nonce در وردپرس را ببینید.

استفاده از wpApiSettings در فرانت‌اند

<?php
wp_enqueue_script( "wpk-api", get_theme_file_uri( "assets/js/api.js" ), array( "wp-api-fetch" ), "1.0.0", true );
wp_localize_script( "wpk-api", "wpApiSettings", array(
    "root"  => esc_url_raw( rest_url() ),
    "nonce" => wp_create_nonce( "wp_rest" ),
) );

OAuth در REST API وردپرس

OAuth روش استاندارد احراز هویت برای اپلیکیشن‌های ثالث است. در وردپرس، OAuth 1.0a و OAuth 2.0 از طریق Pluginهای اختصاصی پشتیبانی می‌شود.

Flow OAuth 2.0:
1. Client درخواست Authorization Code می‌دهد.
2. کاربر در صفحه وردپرس تأیید می‌کند.
3. Client کد را با Access Token مبادله می‌کند.
4. Access Token در Header Authorization ارسال می‌شود.

OAuth برای اپلیکیشن‌های بزرگ مناسب است اما پیچیدگی بالایی دارد. برای اپ موبایل، JWT گزینه ساده‌تری است.

مقایسه Application Password و OAuth

معیارApplication PasswordOAuth 2.0
پیچیدگیکمزیاد
مناسب اپ موبایلبلهبله
لغو از راه دوربلهبله
Refresh Tokenخیربله

permission_callback و مدیریت دسترسی

در register_rest_route، پارامتر permission_callback تعیین می‌کند چه کسی مجاز به دسترسی است.

<?php
register_rest_route( "wpk/v1", "/orders", array(
    "methods"             => "GET",
    "callback"            => "wpk_get_orders",
    "permission_callback" => function() {
        return current_user_can( "manage_woocommerce" );
    },
) );

الگوی حرفه‌ای این است که همیشه از current_user_can() استفاده کنید و هرگز __return_true را روی Endpoint حساس نگذارید.

تفکیک دسترسی خواندن و نوشتن

"permission_callback" => function( $request ) {
    $method = $request->get_method();
    if ( "GET" === $method ) {
        return current_user_can( "read" );
    }
    return current_user_can( "edit_posts" );
}

پاسخ‌های خطای استاندارد

پاسخ‌های خطا باید استاندارد REST API وردپرس را رعایت کنند.

<?php
if ( ! is_user_logged_in() ) {
    return new WP_Error(
        "wpk_unauthorized",
        "دسترسی غیرمجاز. لطفاً وارد شوید.",
        array( "status" => 401 )
    );
}

if ( ! current_user_can( "manage_options" ) ) {
    return new WP_Error(
        "wpk_forbidden",
        "شما مجاز به این عمل نیستید.",
        array( "status" => 403 )
    );
}

برای مطالعه بیشتر، راهنمای تابع rest_ensure_response در وردپرس را ببینید.

کدهای خطای رایج

کدمعنازمان استفاده
401Unauthorizedکاربر وارد نشده
403Forbiddenکاربر وارد شده اما مجاز نیست
404Not Foundمنبع وجود ندارد
422Unprocessableداده نامعتبر

تست و دیباگ احراز هویت

تست احراز هویت در سه سطح انجام می‌شود: سطح کلاینت، سطح سرور و سطح End-to-End.

# تست بدون احراز هویت
curl -i https://example.com/wp-json/wp/v2/posts

# پاسخ مورد انتظار
HTTP/2 401
{"code":"rest_cannot_create","message":"..."}

# تست با Application Password
curl -i -u "username:xxxx xxxx xxxx" https://example.com/wp-json/wp/v2/posts

# پاسخ مورد انتظار
HTTP/2 200

برای تست‌های خودکار، راهنمای تست E2E وردپرس با Playwright را ببینید.

اشتباهات رایج در تست

اشتباه اول، نبود تست با کاربر غیرمجاز. اشتباه دوم، نبود تست با توکن منقضی. اشتباه سوم، نبود تست بدون HTTPS. اشتباه چهارم، نبود تست با Rate Limit. اشتباه پنجم، نبود تست Logout.

اشتباهات امنیتی رایج

سه اشتباه رایج که در پروژه‌های واقعی دیده‌ام:

  1. permission_callback => __return_true روی Endpoint حساس.
  2. استفاده از Basic Auth با رمز اصلی در تولید.
  3. ذخیره توکن در LocalStorage بدون محافظت.
// اشتباه
"permission_callback" => "__return_true"

// درست
"permission_callback" => function() {
    return current_user_can( "edit_posts" );
}

برای مطالعه بیشتر، راهنمای Escape کردن خروجی برای جلوگیری از XSS را ببینید. همچنین مفهوم Authentication را در ویکی‌پدیا مرور کنید.

Rate Limiting برای Endpoint عمومی

add_action( "rest_api_init", function() {
    $ip  = $_SERVER["REMOTE_ADDR"] ?? "";
    $key = "wpk_rate_" . md5( $ip );
    $hits = (int) get_transient( $key );
    if ( $hits > 60 ) {
        header( "HTTP/1.1 429 Too Many Requests" );
        exit;
    }
    set_transient( $key, $hits + 1, MINUTE_IN_SECONDS );
} );

پرسش‌های پرتکرار درباره REST API Auth

تفاوت Application Password و OAuth چیست؟

Application Password ساده‌تر است و برای اپ موبایل کافی است. OAuth برای اپلیکیشن‌های بزرگ با نیاز به Refresh Token مناسب است.

آیا Basic Auth در تولید امن است؟

فقط با HTTPS و API Key اختصاصی. هرگز با رمز اصلی کاربر.

آیا Nonce برای اپ موبایل کار می‌کند؟

خیر، Nonce برای درخواست‌های Same-Origin است. برای اپ موبایل از Application Password یا JWT استفاده کنید.

چرا Endpoint من 401 برمی‌گرداند؟

احتمالاً Header Authorization ارسال نشده یا فرمت آن اشتباه است.

آیا می‌توان چند روش احراز هویت را همزمان استفاده کرد؟

بله، وردپرس از چند روش پشتیبانی می‌کند اما توصیه می‌کنم برای هر کلاینت یک روش مشخص انتخاب کنید.

آیا Application Password با کاربران قدیمی کار می‌کند؟

بله، از وردپرس ۵.۶ برای همه کاربران فعال است.

نتیجه و مسیر ادامه

احراز هویت REST API ستون امنیتی هر اتصال خارجی در وردپرس است. کلید موفقیت، انتخاب درست روش احراز هویت، HTTPS اجباری، permission_callback دقیق، پاسخ خطای استاندارد و تست در سه سطح است. اگر این لایه‌ها با دقت طراحی شوند، پروژه در برابر حملات خارجی پایدار می‌ماند.

پیشنهاد می‌کنم مسیر یادگیری را با JWT Authentication برای REST API ادامه دهید و سپس Custom Table و ساختار داده سفارشی را به‌عنوان مکمل مطالعه کنید.

اگر روی پروژه واقعی خود احراز هویت REST پیاده کرده‌اید، برایم جالب است بدانید کدام روش — Application Password یا OAuth — بیشترین چالش را ایجاد کرده است. تجربه خودتان را در دیدگاه‌ها بنویسید.