وقتی اتصال اپلیکیشن، افزونه یا اسکریپت به /wp-json/ با خطای 401 Unauthorized یا 403 Forbidden مواجه میشود، ابتدا باید مشخص کنید پاسخ را خود وردپرس داده یا لایهای مانند فایروال، CDN یا وبسرور. در بیشتر سناریوها 401 به نبود احراز هویت معتبر و 403 به نداشتن مجوز، nonce نامعتبر یا محدودیت امنیتی مربوط است؛ اما فقط با کد HTTP نمیتوان علت قطعی را تشخیص داد. این راهنما یک مسیر عملی برای تشخیص، اصلاح و آزمون دوباره REST API وردپرس ارائه میکند.
تفاوت خطای 401 و 403 در REST API وردپرس
درخواست به مسیرهای عمومی مانند /wp-json/ و /wp-json/wp/v2/posts معمولاً بدون ورود کار میکند. در مقابل، مسیرهایی مانند /wp-json/wp/v2/users/me به هویت معتبر نیاز دارند. اگر پاسخ JSON شامل rest_not_logged_in باشد، ابتدا احراز هویت را بررسی کنید. اگر کدهایی مانند rest_forbidden یا rest_cannot_edit دیده میشود، نقش کاربر و مجوز همان endpoint را بررسی کنید. پاسخ HTML از WAF یا Cloudflare مسیر متفاوتی دارد.
خطای rest_cookie_invalid_nonce در درخواستهای مبتنی بر کوکی مرورگر نشانه خرابی یا انقضای nonce است؛ این خطا با اشتباه بودن Application Password یکسان نیست. برای بررسی سطح دسترسی کاربران وردپرس میتوانید راهنمای مرتبط آکادمی را بخوانید.
پیشنیازها و سناریوی عیبیابی
- دسترسی مدیریتی به وردپرس و یک کاربر آزمایشی با نقش مناسب؛ دسترسی SSH یا لاگ وبسرور در صورت امکان.
- آدرس HTTPS سایت، ابزار
curlو امکان مشاهده پاسخ کامل HTTP. - یک نسخه پشتیبان از تنظیمات وبسرور، WAF و افزونههای امنیتی پیش از تغییر.
- نمونهها برای
https://example.comهستند؛ آن را با دامنه خودتان جایگزین کنید.
فرض کنید سرویس CRM میخواهد نوشتههای وردپرس را از طریق REST API بخواند یا ایجاد کند، اما 401 دریافت میکند. هدف این است که ابتدا دسترسی عمومی API را بررسی کنیم، سپس با Application Password هویت را آزمایش کنیم و در صورت نیاز، مجوز و تنظیمات سرور را اصلاح کنیم؛ بدون غیرفعالکردن امنیت کل سایت.
مرحله ۱: بررسی دسترسی پایه به wp-json و شناسایی تولیدکننده خطا
در ترمینال، دامنه واقعی را جایگزین کنید و سه درخواست جدا بفرستید:
curl -sS -i 'https://example.com/wp-json/'
curl -sS -i 'https://example.com/wp-json/wp/v2/posts?per_page=1'
curl -sS -i 'https://example.com/wp-json/wp/v2/users/me'برای درخواست اول معمولاً 200 همراه با JSON حاوی namespaces و routes انتظار میرود. درخواست دوم برای نوشتههای منتشرشده معمولاً 200 است. درخواست سوم بدون احراز هویت معمولاً 401 با خطای rest_not_logged_in برمیگرداند؛ این رفتار بهخودیخود خرابی REST API نیست.
هدر Content-Type و متن پاسخ را کنار کد HTTP ببینید. اگر پاسخ JSON با فیلدهای code، message و data.status است، احتمالاً از خود وردپرس آمده؛ اگر صفحه HTML مسدودسازی یا challenge میبینید، سراغ WAF، CDN یا تنظیمات وبسرور بروید. اگر بهجای JSON ریدایرکتهای پیاپی رخ میدهد، راهنمای رفع خطای Too Many Redirects در وردپرس و Cloudflare کمک میکند.
مرحله ۲: احراز هویت امن با Application Password
برای اتصال سرور به سرور، در نسخههای پشتیبانیشده وردپرس، از Application Password مخصوص همان اتصال استفاده کنید؛ این رمز جایگزین رمز اصلی ورود نیست و میتوان آن را جداگانه لغو کرد. از بخش کاربران ← شناسنامه شما ← Application Passwords یک نام مشخص مانند crm-integration انتخاب کنید و رمز تولیدشده را فقط در Secret Manager یا محل امن سرویس نگه دارید. دسترسی API باید روی HTTPS انجام شود.
در یک محیط آزمایشی محلی، برای جلوگیری از ثبت مستقیم رمز در تاریخچه دستورات، آن را تعاملی وارد کنید:
read -r -p 'WordPress username: ' WP_USER
read -r -s -p 'Application password: ' APP_PASS
echo
curl -sS -i --user "$WP_USER:$APP_PASS"
'https://example.com/wp-json/wp/v2/users/me'
unset APP_PASSاگر احراز هویت و مجوزها درست باشند، پاسخ باید 200 و مشخصات همان کاربر باشد. در محیط چندکاربره توجه کنید آرگومانهای خط فرمان بعضی ابزارها ممکن است برای سایر پردازشها قابل مشاهده باشند؛ برای تولید، رمز را در Secret Manager و روش احراز هویت مناسب برنامه نگهداری کنید، نه در اسکریپت عمومی یا مخزن Git. همچنین خروجی کامل پاسخ را در لاگ عمومی حاوی داده حساس ذخیره نکنید.
اگر رمز Application Password در شناسنامه نمایش داده نمیشود، پیش از نصب افزونه ناشناس، HTTPS، سیاست امنیتی سایت و فیلترهای غیرفعالکننده این قابلیت را بررسی کنید. برای اتصال بیرونی از رمز حساب اصلی مدیر استفاده نکنید.
مرحله ۳: اگر Application Password صحیح است ولی همچنان 401 میگیرید
یک بار با همان نام کاربری و رمز روی مسیر /users/me آزمایش کنید. اگر پاسخ همچنان rest_not_logged_in است، بررسی کنید هدر Authorization در مسیر CDN، Reverse Proxy و PHP به وردپرس میرسد یا نه. این مشکل با اشتباه بودن نقش کاربر تفاوت دارد.
در Apache یا LiteSpeed، قوانین پیشفرض فعلی وردپرس در فایل .htaccess را بررسی کنید. اگر مسیر شما به PHP هدر Authorization را منتقل نمیکند، تنظیم مربوط به آن را فقط مطابق مستندات وبسرور و پس از تهیه نسخه پشتیبان اضافه یا اصلاح کنید:
# Apache .htaccess — use only if your server needs this forwarding rule
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]در NGINX با PHP-FPM، مطمئن شوید بلوک واقعی location ~ .php$ و تنظیمات FastCGI هدر را حذف نکرده است. در پیکربندی مناسب ممکن است این پارامتر لازم باشد:
# Inside the actual PHP FastCGI location, not as a standalone config
fastcgi_param HTTP_AUTHORIZATION $http_authorization;پیکربندی نهایی به include fastcgi_params یا include fastcgi.conf و ساختار واقعی سرور بستگی دارد. قبل از اعمال تغییر روی NGINX، دستور nginx -t را اجرا کنید و فقط در صورت موفقیت سرویس را reload کنید. برای Apache نیز apachectl configtest مناسب است. هیچ تغییری را بدون مشاهده علت واقعی در سرور اعمال نکنید.
مرحله ۴: تشخیص خطای 403 و بررسی Capability کاربر
اگر /users/me با Application Password پاسخ 200 میدهد اما درخواست ایجاد یا ویرایش نوشته 403 میگیرد، مشکل احتمالاً احراز هویت نیست. کاربر باید مجوز مناسب مانند edit_posts یا publish_posts برای عملیات مورد نظر داشته باشد؛ این مجوزها با نقش، نوع نوشته و مالکیت محتوا تغییر میکنند. برای آزمایش خواندن، از endpoint مجاز استفاده کنید؛ برای تست نوشتن، فقط در سایت staging یک نوشته آزمایشی ایجاد کنید و بعد حذفش کنید.
نمونه درخواست بررسی نوشتههای قابلویرایش:
# Requires a valid Application Password and sufficient permissions
curl -sS -i --user "$WP_USER:$APP_PASS"
'https://example.com/wp-json/wp/v2/posts?context=edit&per_page=1'اگر این دستور را بعد از unset APP_PASS اجرا میکنید، ابتدا رمز را دوباره بهصورت امن وارد کنید. اگر در پاسخ rest_cannot_edit یا rest_forbidden_context دیدید، نقش کاربر و مجوز endpoint را بررسی کنید؛ ارتقای بیدلیل همه کاربران به Administrator راهحل امنی نیست.
مرحله ۵: خطای 403 ناشی از nonce در درخواستهای مرورگر
برای Ajax یا JavaScript اجراشده داخل محیط وردپرس که با کوکی ورود کار میکند، WordPress REST API از nonce با action برابر wp_rest استفاده میکند. nonce معمولاً با هدر X-WP-Nonce ارسال میشود. اگر nonce نامعتبر یا منقضی باشد، وردپرس میتواند 403 rest_cookie_invalid_nonce بدهد. اگر nonce اصلاً ارسال نشود، درخواست ممکن است بهصورت مهمان پردازش شود و برای endpoint خصوصی به 401 برسد.
// In WordPress PHP, enqueue the script and pass a REST nonce safely
wp_localize_script('my-app', 'myRest', [
'url' => esc_url_raw(rest_url()),
'nonce' => wp_create_nonce('wp_rest'),
]);
// In JavaScript running in the authenticated browser:
fetch(myRest.url + 'wp/v2/users/me', {
headers: { 'X-WP-Nonce': myRest.nonce },
credentials: 'same-origin'
}).then(r => r.json()).then(console.log);این نمونه برای کد داخل سایت است، نه اتصال سرور به سرور. nonce جایگزین بررسی مجوز یا رمز API نیست و نباید در صفحه کششده عمومی برای همه بازدیدکنندگان منتشر شود. اگر مشکل همزمان با ورود و خروج کاربران رخ میدهد، تنظیم کوکی و کش را نیز بررسی کنید؛ مقاله عیبیابی خطاهای کوکی وردپرس مرتبط است.
مرحله ۶: بررسی افزونه امنیتی، Cloudflare و WAF بدون خاموشکردن حفاظت
اگر 403 بهصورت HTML برمیگردد یا در لاگ وردپرس هیچ اثری از درخواست نیست، ابتدا هدرهای پاسخ، زمان درخواست، IP مبدأ و شناسه Rule/Request در پنل WAF را بررسی کنید. اگر Cloudflare استفاده میکنید، رویدادهای Security Events را با زمان و IP همان درخواست تطبیق دهید. در ModSecurity نیز لاگ Audit را بررسی کنید.
بهجای غیرفعالکردن کل فایروال یا آزادکردن عمومی /wp-json/*، برای endpoint مشخص و مبدأ قابلاعتماد، یک استثنای محدود و قابل بازگشت تعریف کنید؛ فقط وقتی لاگ نشان میدهد Rule مشخص باعث False Positive شده است. اگر افزونهای REST API را برای کاربران مهمان مسدود کرده، بررسی کنید محدودیت برای مسیر عمومی هم اعمال شده یا فقط مسیرهای خصوصی. API عمومی را برای رفع 401 خصوصی باز نکنید.
مرحله ۷: اگر endpoint سفارشی وردپرس 403 میدهد
در افزونههای سفارشی، ثبت مسیر با register_rest_route باید permission_callback داشته باشد. اگر endpoint خصوصی است، مجوز را با current_user_can بررسی کنید؛ مقدار __return_true فقط برای endpoint واقعاً عمومی مناسب است. مثال حداقلی:
add_action('rest_api_init', function () {
register_rest_route('myplugin/v1', '/reports', [
'methods' => 'GET',
'callback' => 'myplugin_get_reports',
'permission_callback' => function () {
return current_user_can('manage_options');
},
]);
});این قطعه تنها نمونه بررسی مجوز است و تابع myplugin_get_reports باید جداگانه بهصورت امن تعریف شده باشد. در endpoint واقعی، ورودیها را اعتبارسنجی و خروجی حساس را کنترل کنید. اگر کاربر مجوز ندارد، نباید برای حذف خطا شرط دسترسی را بردارید.
مرحله ۸: تست نهایی و ثبت شواهد رفع مشکل
بعد از هر تغییر فقط همان درخواست ناموفق را تکرار کنید و کد HTTP، Content-Type و فیلد code پاسخ JSON را مقایسه کنید. جدول زیر برای تفکیک نتیجه مفید است:
| آزمایش | نتیجه قابل انتظار | اگر نتیجه متفاوت بود |
|---|---|---|
GET /wp-json/ | 200 و JSON | Rewrite، WAF، کش یا مسدودسازی عمومی API |
GET /wp/v2/users/me بدون هویت | 401 از وردپرس | وجود session/cookie یا رفتار افزونه |
GET /wp/v2/users/me با Application Password | 200 و شناسه کاربر | رمز، HTTPS یا عبور Authorization |
| درخواست خصوصی با کاربر کممجوز | 403 یا خطای مجوز | Role/Capability و endpoint |
برای کنترل سریع هدرها و پاسخ بدون نمایش خروجی کامل در ترمینال، این روش را روی محیط امن اجرا کنید:
curl -sS -D /tmp/wp-api-headers.txt -o /tmp/wp-api-body.json
-w 'HTTP %{http_code}n' 'https://example.com/wp-json/'
head -n 20 /tmp/wp-api-headers.txt
head -c 500 /tmp/wp-api-body.jsonفایلهای موقت ممکن است دادههای پاسخ را نگه دارند؛ روی سرور مشترک با مجوز محدود ذخیره کنید و پس از پایان بررسی پاک کنید.
بازگشت امن تغییرات و پیشگیری از تکرار خطا
- اگر قانون جدید WAF یا استثنای Cloudflare باعث بازشدن دسترسی بیش از حد شد، همان قانون محدود را حذف و رویدادهای امنیتی را دوباره بررسی کنید.
- اگر پس از ویرایش
.htaccessیا NGINX مشکل تازهای ایجاد شد، نسخه پشتیبان فایل را برگردانید، اعتبار پیکربندی را تست کنید و سرویس را reload کنید. - Application Password آزمایشی را پس از اتمام تست لغو کنید؛ رمزها را در Git، اسکرینشات یا تیکت پشتیبانی قرار ندهید.
- برای یکپارچهسازی دائمی، کاربر سرویس با حداقل Capability لازم، HTTPS، ثبت خطاهای بدون اطلاعات حساس و تست پس از بهروزرسانی افزونهها داشته باشید.
اگر مشکل به پیکربندی PHP، Rewrite یا محدودیتهای میزبانی مربوط است و به مدیریت مستقیم سرور دسترسی ندارید، بررسی امکانات و محدودیتهای پلنهای هاست وردپرس و سیپنل وانسرور میتواند برای انتخاب محیط مناسب کمککننده باشد؛ خرید هاست بهتنهایی خطای 401 یا 403 را رفع نمیکند.
منابع فنی
- WordPress Developer — Authentication
- WordPress Developer — Routes and permission_callback
- WordPress Core — Application Passwords Integration Guide