این صفحهٔ ستون خوشهٔ «امنیت هاست و وردپرس» است. معیارم برای آوردن هر مورد در این فهرست یک سؤال بوده: اگر این کار را بکنم، دقیقاً کدام مسیر حمله بسته میشود؟ اگر جواب نداشتند، در فهرست جای نگرفتند.
ترتیب هم تصادفی نیست. اول کاری که احتمال وقوع را کم میکند، بعد کاری که خسارت را کوچک میکند، و در آخر کاری که بهت خبر میدهد. اگر وقتت کم است، هفت مورد اول را انجام بده.
پیش از هر چیز: تهدید واقعی از کجا میآید
آمارهای عمومی دربارهٔ «هک وردپرس» بیشتر از آنکه راهنما باشند، بازاریابیاند. چیزی که در پروژههای واقعی میبینم، سه مسیر است و سهمشان نامتقارن:
یک: افزونه یا قالب آلوده از همان اول. فایل نصبشده از جایی غیر از مخزن رسمی، کد مهاجم را در خودش دارد. در این حالت هیچ «رمز قوی» و «افزونهٔ امنیتی» تو را نجات نمیدهد، چون مهاجم از درِ اصلی آمده است.
دو: حساب ضعیف یا بازیافتشده. رمز مدیر، رمز FTP، یا رمز پنل هاست. اگر یک رمز در چند جا استفاده شده باشد و یک سرویس افشا کند، درِ تو هم باز است.
سه: هسته، قالب یا افزونهٔ بهروزنشده با آسیب شناختهشده. اسکنرهای خودکار، نسخهٔ تو را از readme یا از اثر انگشت فایل میخوانند و بعد از انتشار آسیب، ساعتها طول نمیکشد.
تقریباً همیشه، همین سه. پس امنیت یعنی بستن همین سه، نه نصب افزونهٔ ششم.
یک: ویرایش فایل از پیشخوان را ببند
وردپرس بهصورت پیشفرض ویرایشگر قالب و افزونه را درون پیشخوان باز میگذارد. اگر مهاجم به حساب مدیر برسد، از همانجا کد مینویسد و لازم نیست فایل آپلود کند. بستنش یک خط است:
define( 'DISALLOW_FILE_EDIT', true );این جلوی ورود را نمیگیرد، ولی مرحلهٔ بعد از ورود را حذف میکند و همیشه باید روشن باشد. نکته: بعضی افزونههای ویرایش CSS هم از همین مسیر رد میشوند؛ بعد از روشنکردن، یک بار مسیر ظاهرِ سفارشیسازی را تست کن.
دو: مسیر بارگذاری را از اجرای PHP جدا کن
مسیر آپلود، پرمخاطبترین نقطه برای کاشتن فایل PHP است. روی سیپنل با لایتاسپید، بستن اجرا در آن پوشه قابلانجام است:
<FilesMatch "\.ph(p[3-9]?|tml|ar)?$">
Require all denied
</FilesMatch>قبل از اعمال، یک سؤال بپرس: افزونهای داری که فایل PHP داخل مسیر بارگذاری میگذارد؟ بعضی سازندههای صفحه و کشهای خاص این کار را میکنند. اگر دارند، بهجای بستن کل پوشه، فایلهای خاص را استثنا کن یا آنها را به مسیر دیگری منتقل کن. بهتر است اول روی محیط استیج امتحان کنی، چون نشانهٔ شکست، صفحهٔ ۵۰۰ است بیتوضیح.
سه: دسترسی نوشتن روی فایلها را واقعی ببین
اعداد ۶۴۴ برای فایل و ۷۵۵ برای پوشه، نقطهٔ شروعاند نه پایان کار. مهمتر از عدد، مالک فایل است. اگر فایلها مالک root باشند و PHP با کاربر اکانت اجرا شود، نه مهاجم مینویسد نه تو بهراحتی آپدیت میکنی؛ و اگر برعکس، همهچیز نوشتنی است.
دو بررسی کوتاه:
ls -la public_html | head
find public_html -type f -perm -o=wخروجی دوم باید خالی باشد. هر فایلی که برای «بقیه» نوشتنی است، یا اشتباه دسترسی خورده یا قبلاً چیزی در آن نوشته شده.
چهار: نقشها را به اندازهٔ نیاز پایین بیاور
بیشترین خسارت از حساب مدیر کل میآید که لازم نبود مدیر کل باشد. در یک پروژهٔ واقعی، چند نقش مدیر کل دیدم که فقط برای «یک بار تغییر» ساخته شده بودند و سالها همانطور ماندند.
قاعدهٔ ساده: کسی که محتوا مینویسد، Editor باشد. کسی که ووکامرس را اداره میکند، نقش Shop Manager. مدیر کل فقط برای کسانی که واقعاً روی تنظیمات، افزونه و کاربران کار میکنند. فهرست فعلی را با یک کوئری کوتاه ببین:
SELECT user_login, meta_value FROM wp_usermeta
WHERE meta_key = 'wp_capabilities';پنج: کلیدهای نمک را عوض کن و روتین کن
هشت کلید امنیتی در wp-config.php نشستها را امضا میکنند. اگر نشتی داشته باشی، یا بعد از هر آلودگی، این کلیدها را عوض کن تا همهٔ نشستهای فعال بیاعتبار شوند. تولید تصادفی مناسب کافی است؛ فقط یادت باشد که با تعویض، همه از پنل خارج میشوند.
درستکردن این مورد را عقب ننداز: نشستنِ نشست دزدیدهشده، همان چیزی است که باعث میشود «رمز را عوض کردم ولی دوباره هک شد».
شش: REST API و دسترسیهای علنی را محدود کن
همین الان روی سایتهای بسیاری، فهرست نوشتهها، شناسهٔ نویسندگان و نام قالب و افزونه از مسیر REST قابل خواندن است. این اطلاعات، نقشهٔ حمله میسازد: مهاجم میفهمد چه چیزی نصب است و چه نسخهای.
سه سطح پاسخ: بستن کامل برای ناشناس، فقط خواندن مجاز، یا بیتغییری. برای سایت معرفی و بلاگ، معمولاً بستن فهرست کاربران و نگهداشتن خواندن نوشتهها تعادل خوب است. روش را در مقالهٔ جدا در همین خوشه باز کردهام.
هفت: xmlrpc را اگر لازم نداری ببند
xmlrpc.php برای اتصال اپلیکیشن موبایل و برخی سرویسها لازم است، و همزمان مسیر حملهٔ force-get و پرسوجوی انبوه است. اگر از این اتصالها استفاده نمیکنی، بستنش یک تصمیم آسان و بیهزینه است. اگر استفاده میکنی، دستکم تلاشهای مکرر به این مسیر را در پایش بگیر.
هشت: بهروزرسانی، اما نه کورکورانه
ماندَن پشت نسخه، ریسک اصلی است؛ ولی «همه را یکجا و بدون تست» هم ریسک است. روشی که کار میکند:
۱. نسخهٔ پشتیبانِ فایل و دیتابیس، پیش از هر بهروزرسانی. ۲. اول افزونهها یکییکی، با یک تست کوتاه بعد از هر کدام. ۳. قالب و هسته در آخر. ۴. بعد از اتمام، سه مسیر را دستی برو: صفحهٔ اصلی، ورود، فرم تماس.
افزونهای که دو سال بهروز نشده و در سایتت هم چیزی انجام نمیدهد، حذف میشود؛ نگهداشتنش «برای بعداً» دلیل ندارد. هر افزونهٔ اضافه، یک ورودی است با تاریخ انقضای نامعلوم.
نه: افزونههای رهاشده و ردِ آنها در دیتابیس
حذف افزونه، ردپایش را پاک نمیکند: کلیدهای سریالشده در جدول گزینهها، میزهای اختصاصی در دیتابیس، و فایلهای جامانده در مسیر بارگذاری. اینها دو مشکل میسازند: یکی کندی، دیگر سطح حملهٔ خاموش.
بعد از حذف هر افزونه: مسیر بارگذاری و ریشهٔ wp-content را برای نام آن افزونه بگرد، و اگر جدول اختصاصی ساخت بود، با آگاهی حذفش کن. روش شمارش کلیدهای بزرگ را در مقالهٔ مربوط به جدول گزینهها آوردهام.
ده: ورود دومرحلهای، با احتساب محدودیتهای ما
ورود دومرحلهای، احتمال موفقیت حملهٔ مبتنی بر رمز را بهشدت پایین میآورد؛ تقریباً مؤثرترین تکاقدام در این فهرست است. ولی دو نکتهٔ بازار ما:
بعضی سرویسهای پیامرسانی احراز در دسترس نیستند یا قطعی دارند. روش مبتنی بر برنامهٔ احراز آفلاین، معمولاً قابلاتکاتر از پیامک است.
قفلشدن، هزینهٔ واقعی دارد. پیش از فعالسازی، یک حساب مدیر پشتیبان با روش دیگر داشته باش و کدهای بازیابی را جای امن نگه دار. سایتی که بهخودش وارد نمیشود، امن نیست؛ فقط دسترسناپذیر است.
یازده: لاگ ورود ناموفق را ببین، نه فقط گزارشاش
افزونهای که «۱۲۰ تلاش ناموفق» را در داشبورد نشان میدهد، کاری نمیکند. ارزش در اقدام لایهٔ پایینتر است: اگر دسترسی به سرور داری، fail2ban یا محدودسازی در سطح وبسرور؛ اگر نداری، دستکم مسیر ورود را عوض کن تا حجم رباتهای عمومی پایین بیاید، و لاگ را هفتگی نگاه کن.
نکته: تغییر آدرس ورود، امنیتی جدی نیست؛ فقط نویز را کم میکند. آن را جایگزین رمز قوی حساب نکن.
دوازده: نسخهٔ PHP را تازه نگهدار
نسخهٔ قدیمی PHP هم خطر امنیتی دارد هم هزینهٔ کارایی. روی سیپنل، هر اکانت نسخهٔ خودش را دارد، پس بررسی را برای هر اکانت جدا انجام بده و پیش از تغییر، سازگاری قالب و افزونهها را در استیج ببین.
یک احتیاط عملی: بعد از تغییر نسخه، کش bytecode همان اکانت را تازه کن. اگر این کار را نکنی، فایلهای تازه را با کد قدیمی اجرا میبینی و نتیجه میگیری «تغییر اثر نکرد»؛ همان تلهای که دربارهاش مقاله جدا دارم.
سیزده: فهرست هش بساز و هفتگی مقایسه کن
ارزانترین تشخیص تغییر غیرمجاز، فهرست هش است. یک بار بساز:
find public_html -type f -name "*.php" -exec sha256sum {} \; > /home/user/php-hashes.txtهفتهای یک بار فهرست تازه بساز و اختلاف را ببین. هر فایل PHP تازهشده که خودت نساختهای، باید توضیح داشته باشد. این روش ساده، بیشتر آلودگیها را هفتهها زودتر از شکایت میزبان نشان میدهد.
چهارده: بکاپی که تست نشده، بکاپ نیست
بیشترین خسارت را جایی میبینیم که بکاپ بوده ولی بازگردانیاش آزموده نشده بود. یک بار در ماه، یک فایل از بکاپ را روی محیط تست بالا بیاور و سه چیز را چک کن: ورود به پیشخوان، یک صفحهٔ درونخطی، و فرم تماس. اگر بکاپ کامل سیپنل میگیری، بدان که داخلش چه چیزهایی نیست و ایمیل و DNS را جدا نگه دار.
پانزده: امنیت را در یک چرخه ببین، نه یک نصب
هیچکدام از این پانزده مورد، «انجام شد» نیستند؛ همگی نیاز به بازبینی دارند، چون سطح حمله با هر افزونهٔ تازه عوض میشود. یک چرخهٔ ماهانهٔ بیستدقیقهای کافی است:
۱. شمار کاربران مدیر کل و نقشها. ۲. افزونههای غیرفعال یا رهاشده. ۳. بهروزرسانیهای معوق و نسخهٔ PHP. ۴. مقایسهٔ فهرست هش. ۵. یک نگاه به لاگ ورود و خطاها. ۶. تست کوتاه بازگردانی از بکاپ.
مرز بین امنسازی و خرابکردن سایت
پیش از ادامه، یک هشدار که کمتر دربارهاش نوشته میشود: بیشترِ شکستهای امنیتی که من دیدهام، حمله نبودند؛ تنظیمات امنیتیِ بیآزمون بودند. سه نمونهٔ واقعی:
بستن کل wp-admin با رمز دوم، درحالیکه فرم ورود membership از همان مسیر استفاده میکرد و سایت برای کاربر عادی عملاً از کار افتاد.
قاعدهٔ generic در .htaccess که مسیرهای بازگشت درگاه پرداخت را هم بست؛ نتیجهاش سفارشهایی بود که پرداخت میشدند ولی تأیید نمیرسیدند. این نوع خرابی خطرناک است چون نشانهٔ خطا ندارد: کاربر پول میدهد و تو نفهمیدهای.
فعالسازی «تشریق بات» در افزونهٔ امنیتی که روی ترافیک ایران، کاربر واقعی را هم بهعنوان ربات میشناخت. صفحهٔ سایت باز میماند ولی فرم هرگز ارسال نمیشد.
قاعدهای که از این سه درس گرفتم: هر محدودسازی، روی استیج یا با یک حساب آزمایشی، اول شکستنش را امتحان کن. امنسازی که مسیر پولساز را ببندد، بهجای امنیت، ضرر میدهد. و بعد از هر تغییر، لاگ دسترسی را در نیمساعت اول نگاه کن: اگر الگوی غیرعادی ندیدی، تمام است.
دوازدهم تا پانزدهم را چطور زمانبندی کنی
پانزده مورد، یکروز انجام نمیشوند؛ و اگر یکروز انجامشان بدهی، احتمال شکستن سایت بالاست. زمانبندیای که در پروژهها جواب داده:
روز اول، بیست دقیقه: DISALLOW_FILE_EDIT، فهرست کاربران مدیر کل، و شمارش افزونههای غیرفعال. این سه هیچ ریسکی ندارند و سودشان فوری است.
روز دوم، یک ساعت: بکاپ و تست بازگردانی روی محیط تست. تا این انجام نشود، سراغ هیچ تغییر فنی نرو.
هفتهٔ اول: ورود دومرحلهای برای حسابهای مدیر، با حساب پشتیبانِ آماده. بعد بستن اجرا در مسیر بارگذاری، فقط روی استیج و با تست آپلود تصویر.
هفتهٔ دوم: REST API و xmlrpc، هر کدام جدا، با یک تست بعد از هر تغییر.
هفتهٔ سوم: بهروزرسانیهای معوق، یکییکی، و بعد بررسی نسخهٔ PHP.
پایان ماه: فهرست هش پایه، و تنظیم چرخهٔ ماهانه.
دلیل این ترتیب، وابستگی است: تا بکاپِ تستشده نداشته باشی، هر مورد دیگر پتانسیل خرابی دارد. و تا نسخهٔ هش پایه نساخته باشی، تشخیص تغییر غیرمجاز عملاً ممکن نیست.
یک نمونه: امنسازی روی سایتی که تازه آلوده شده بود
سایت خدماتی با حدود نود نوشته، دو بار در سه ماه آلوده شده بود و میزبان دو بار اخطار ارسال کرده بود. وضعیت وقتی دیدمش:
هفت حساب مدیر کل، که سهتایشان سالها استفاده نشده بودند. سه افزونهٔ غیرفعال که فقط دادهشان در دیتابیس مانده بود. یک قالب قدیمی در پوشهای که هیچجا به آن ارجاع نمیشد. و xmlrpc.php با حجم قابلتوجهی درخواست روزانه.
کاری که انجام شد، به همین ترتیب: حذف حسابهای بیاستفاده، حذف افزونه و قالب رهاشده، بستن xmlrpc، ورود دومرحلهای برای دو حساب باقیمانده، فهرست هش، و چرخهٔ ماهانه. بدون نصب حتی یک افزونهٔ امنیتی تازه.
نتیجه پس از بازبینی بعدی: درخواستهای مشکوک روی مسیر ورود از بین رفته بود و مقایسهٔ هفتگی هش، اختلاف بیدلیل نشان نمیداد. نکتهٔ آموزنده این است که در آن سایت، چیزی که واقعاً حمله را ممکن میکرد، سه حساب فراموششده و یک فایل رهاشده بود؛ نه نبودِ یک افزونه.
چه زمانی این فهرست کافی نیست
سه موقعیت که باید جدیتر وارد شدی:
ترافیک مالی و دادهٔ شخصی. اگر نشانی، شمارهٔ تماس یا اطلاعات پرداخت نگه میداری، سیاست نگهداری و کمکردن دادهها مهمتر از هر تنظیم فنی میشود.
چند سایت با یک رمز پنل. اگر یک رمز برای چند اکانت هاست استفاده کردهای، یک نفوذ، همه را میبَرَد. این را اول درست کن.
سایتی که قبلاً آلوده شده و مطمئن نیستی پاک شده باشد. در این حالت فهرست بالا پیشنیاز است، نه درمان؛ مسیر درست، بازسازی از منبع رسمی و بازگردانی از بکاپ سالمِ پیش از آلودگی است، که در مقالهٔ جدا توضیح دادهام.
چه چیزی را در این فهرست پیدا نمیکنی
عمداً چند مورد را نیاوردم، چون مانع نمیشوند: «نمایشدهندهٔ امتیاز امنیتی»، «تغییر نام کاربری admin» (اثر واقعی ندارد؛ رمز و ورود دومرحلهای اثر دارند)، «قفلکردن کل wp-admin با رمز دوم» (روی بسیاری سایتها کاربر و فرم را میشکند)، و «نصب افزونهٔ امنیتی چندم». هر افزونهٔ امنیتی هم مثل هر افزونهٔ دیگر، سطح حمله و بار اضافه میآورد.
اگر فقط سه کار میتوانی بکنی: ورود دومرحلهای، بستن اجرای PHP در مسیر بارگذاری، و چرخهٔ بهروزرسانی با بکاپِ تستشده. همین سه، سهم بزرگی از مسیرهای واقعی را میبندند. بقیهٔ خوشه هر کدام یک لایه را باز میکنند: تشخیص آلودگی، بازگردانی بعد از هک، وبشل، و اینکه REST API دقیقاً چه چیزی دربارهٔ سایتت فاش میکند.
مقالبی بخوانی
- وبشل چیست و چطور روی هاست اشتراک پیدا میشود؟
- تفاوت LiteSpeed با Nginx و Apache برای وردپرس؛ کدام وبسرور واقعیت را سریع میکند؟
- اعتبار موضوعی و لینکدهی خوشهای؛ ساختار ستون و خوشه در عمل
- چرا سایت وردپرسی کند است؛ اندازهگیری بهجای حدس
- محتوای انبوه یا Scaled Content Abuse؛ سیاستی که سایتهای پُرمقاله را تنبیه میکند
- شصت روز اول یک پروژهٔ سئو؛ ترتیب واقعی کار
- MySQL یا MariaDB برای وردپرس؛ تفاوت عملی روی هاست سیپنل