پرش به محتوا
سرور و .htaccess

کدهای امنیتی htaccess وردپرس که واقعاً به درد می‌خورند

بیشتر چیزهایی که با عنوان امنیت htaccess وردپرس فروخته می‌شوند فقط پرکردن جای خالی هستند. کدهایی که واقعاً سطح حمله شما را تغییر می‌دهند کوتاه‌اند — اینجا مشخص می‌کنیم کدام کدام است

منتشرشده

بیشتر چیزهایی که با عنوان «امنیت .htaccess وردپرس» فروخته می‌شوند صرفاً پرکردن جای خالی هستند. کدهایی که واقعاً سطح حمله شما را تغییر می‌دهند کوتاه‌اند: جلوگیری از اجرای PHP در داخل wp-content/uploads، مسدود کردن دسترسی مستقیم به wp-config.php و غیرفعال کردن نمایه‌سازی پوشه‌ها (directory indexing). آن‌های پرطرفدار — مسدود کردن xmlrpc.php «برای جلوگیری از حمله brute force»، پنهان کردن نسخه وردپرس، چسباندن یک لیست ۲۰۰ خطی از user-agent ربات‌های مخرب — چیزی بین کم‌اثر تا نمایش محض هستند. در ادامه مشخص می‌کنیم کدام کدام است و چرا.

اول یک نکته را روشن کنیم: .htaccess فقط روی Apache (و LiteSpeed که آن هم این فایل را می‌خواند) کاری انجام می‌دهد. روی nginx به‌کلی نادیده گرفته می‌شود — فایل همان‌جا می‌ماند در حالی که شما فکر می‌کنید محافظت شده‌اید. اگر هاست شما nginx اجرا می‌کند، هیچ‌کدام از این‌ها به کارتان نمی‌آید و به جایش به بلوک‌های server/location نیاز دارید. با curl -I https://yoursite.com بررسی کنید و پیش از آنکه یک ساعت وقت صرف ویرایش فایلی کنید که سرور اصلاً نمی‌خواندش، به هدر Server: نگاه کنید.

کدی که واقعاً اهمیت دارد: بدون PHP در /uploads

این همان کدی است که ارزش انجام دادن دارد. wp-content/uploads طبق طراحی برای همه قابل نوشتن است — هر آپلود رسانه، هر افزونه‌ای که فایلی ذخیره می‌کند، در آنجا می‌نویسد. اگر مهاجمی بتواند یک فایل .php را وارد این پوشه کند (از طریق یک هندلر آپلود آسیب‌پذیر، یک فیلد تصویر که نوع MIME را اعتبارسنجی نمی‌کند، یا یک افزونه آلوده)، تفاوت میان یک دردسر کوچک و یک نفوذ کامل از نوع اجرای کد از راه دور (remote code execution) در این است که آیا سرور آن فایل را هنگام درخواست اجرا می‌کند یا نه. اجرا را مسدود کنید و آنگاه محموله آپلودشده فقط یک فایل بی‌اثر روی دیسک خواهد بود.

این را داخل wp-content/uploads/.htaccess بگذارید (اگر فایل وجود ندارد، آن را بسازید):

<FilesMatch "\.php$">
    Require all denied
</FilesMatch>

این نحو Apache 2.4 است. روی نسخه قدیمی‌تر 2.2، معادلش Order Deny,Allow / Deny from all است. مخلوط کردن این دو گویش در یک فایل رایج‌ترین علت بروز ناگهانی 500 Internal Server Error بعد از «افزایش امنیت» است — اگر لحظه‌ای که ذخیره می‌کنید کل سایت از کار می‌افتد، تقریباً همیشه دلیلش همین است. نسخه خود را با apachectl -v بررسی کنید.

از wp-config.php محافظت کنید

wp-config.php اطلاعات ورود به دیتابیس و کلیدهای salt احراز هویت شما را نگه می‌دارد. تا زمانی که PHP در حال اجراست، یک درخواست مستقیم به آن یک صفحه خالی برمی‌گرداند — PHP فایل را اجرا می‌کند به جای آنکه چاپش کند. خطر در حالت خرابی است: اگر روزی PHP کرش کند، حین یک انتقال (migration) درست پیکربندی نشود، یا هندلرش غیرفعال شود، Apache فایل را به‌صورت متن ساده سرو می‌کند و رمز دیتابیس شما را به هرکسی که بخواهد تحویل می‌دهد. مسدود کردن دسترسی، بیمه‌ای ارزان در برابر پنج دقیقه بد است:

<Files wp-config.php>
    Require all denied
</Files>

نمایه‌سازی پوشه‌ها را خاموش کنید

اگر کسی به پوشه‌ای بدون index.php سر بزند و Apache گزینه Options +Indexes روشن باشد، محتویات آن را لیست می‌کند — هر فایل پشتیبان، هر دامپ SQL سرگردان که فراموشش کرده‌اید. آن را در کل سایت خاموش کنید:

Options -Indexes

شدتش پایین است، اما واقعی است و هزینه‌ای ندارد.

این هم لیست هسته‌ای و صادقانه. می‌توانید این‌ها را — به‌همراه نحو درست 2.4 در برابر 2.2 تا سایتتان 500 نشود — با سازنده htaccess وردپرس بسازید، به جای کپی-پیست کردن از یک پست انجمنی که برای نسخه اشتباه Apache نوشته شده است.

چه کارهایی نکنید

مسدود کردن xmlrpc.php «برای محافظت در برابر brute force». این همان چیز بزرگی است که همه تکرارش می‌کنند و همان‌طور که گفته می‌شود اشتباه است. بله، متد system.multicall در XML-RPC از نظر تاریخی به مهاجم اجازه می‌داد که حدس‌های ورود متعدد را در یک درخواست واحد بسته‌بندی کند — تقویت واقعی حمله. اما رایج‌ترین بردار حمله brute force با اختلاف زیاد، درخواست‌های ساده POST به wp-login.php است و مسدود کردن xmlrpc.php برای آن هیچ کاری نمی‌کند. brute force با محدودسازی نرخ (rate limiting)، رمزهای عبور قوی و احراز هویت دومرحله‌ای شکست می‌خورد — نه با از بین بردن یک نقطه پایانی (endpoint). یک دلیل مشروع برای غیرفعال کردن XML-RPC وجود دارد: قابلیت pingback آن می‌تواند برای بازتاب حملات DDoS سوءاستفاده شود، پس اگر از Jetpack، اپلیکیشن موبایل یا pingback استفاده نمی‌کنید، بستن آن سطح حمله شما را کوچک می‌کند. فقط به خودتان نگویید که این دفاع شما در برابر brute force است، چون نیست.

پنهان کردن نسخه وردپرس / حذف تگ generator. حذف readme.html و تگ <meta name="generator"> حس افزایش امنیت می‌دهد. یک مهاجم نسخه شما را در چند ثانیه از روی رشته‌های کوئری فایل‌های صف‌شده (enqueued asset)، مارک‌آپ ویرایشگر بلوک و ده‌ها نشانه دیگر انگشت‌نگاری می‌کند. شما چیزی را پنهان نمی‌کنید؛ فقط دارید به خودتان حس مشغول بودن می‌دهید.

لیست‌های بزرگ مسدودسازی user-agent ربات‌های مخرب و referrer. user-agent فقط یک هدر HTTP جعلی است. این لیست‌ها همان روزی که کپی‌شان می‌کنید کهنه‌اند، هیچ ربات کاربلدی را مسدود نمی‌کنند، و Apache هر regex را روی هر درخواست ارزیابی می‌کند — شما دارید مالیات کارایی واقعی می‌پردازید برای امنیت صفر. رهایشان کنید.

قفل کردن wp-login.php روی یک IP. عالی است تا زمانی که ISP شما آدرستان را عوض کند و خودتان را از پیشخوان مدیریت خودتان بیرون بیندازید. فقط با یک IP واقعاً ثابت (static) عملی است.

ریدایرکت‌های جلوگیری از شمارش نویسنده (?author=1). بازنویسی .htaccess که مردم برای این کار کپی می‌کنند به‌تنهایی ناقص است — نقطه پایانی REST یعنی /wp-json/wp/v2/users همچنان نام‌های کاربری را لیست می‌کند. مسدود کردن یک مسیر در حالی که مسیر دیگر باز می‌ماند نمایش محض است.

هنوز گیر کرده‌اید؟

اگر یک کد سایت را 500 می‌کند، مشکل نحو است — آخرین بلوکی که اضافه کرده‌اید را بردارید و دوباره بارگذاری کنید؛ این بلافاصله مقصر را مشخص می‌کند. اگر یک کد به نظر می‌رسد هیچ کاری نمی‌کند، مطمئن شوید که واقعاً روی Apache هستید و اینکه AllowOverride برای آن پوشه فعال است (بسیاری از هاست‌های مدیریت‌شده آن را محدود می‌کنند). فایل را از یک قالب سالم و شناخته‌شده با سازنده htaccess بسازید، سه کد مهم را نگه دارید و بقیه را کنار بگذارید.