דילוג לתוכן
שרת ו-.htaccess

כללי אבטחה ל-.htaccess בוורדפרס שבאמת עוזרים

רוב מה שמוכרים כאבטחת .htaccess לוורדפרס הוא מילוי מקום. הכללים שבאמת משנים את משטח התקיפה שלך קצרים — הנה מי מול מי

פורסם

רוב מה שמוכרים כ”אבטחת .htaccess לוורדפרס” הוא מילוי מקום. הכללים שבאמת משנים את משטח התקיפה שלך קצרים: לחסום הרצת PHP בתוך wp-content/uploads, למנוע גישה ישירה ל-wp-config.php, ולכבות את אינדוקס התיקיות. הפופולריים — חסימת xmlrpc.php “כדי לעצור brute force”, הסתרת גרסת וורדפרס, הדבקה של רשימת user-agent בת 200 שורות נגד בוטים — נעים בין שוליים לתיאטרון טהור. למטה מפורט מי מול מי, ולמה.

דבר אחד כדאי לסגור קודם: .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 מחזיק את פרטי הגישה למסד הנתונים ואת מלחי האימות. כל עוד PHP רץ, בקשה ישירה אליו מחזירה עמוד ריק — PHP מריץ את הקובץ במקום להדפיס אותו. הסיכון הוא במקרה הכשל: אם PHP קורס אי פעם, מוגדר שגוי במהלך מיגרציה, או שהמטפל מושבת, 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, סיסמאות חזקות, ו-2FA — לא על ידי הריגת endpoint אחד. יש סיבה לגיטימית להשבית XML-RPC: תכונת ה-pingback שלו ניתנת לניצול להחזרת DDoS, אז אם אתה לא משתמש ב-Jetpack, באפליקציית המובייל, או ב-pingbacks, סגירתו מצמצמת את משטח התקיפה שלך. פשוט אל תספר לעצמך שזו ההגנה שלך מפני brute force, כי היא לא.

הסתרת גרסת וורדפרס / הסרת תג ה-generator. הפשטת readme.html ותג ה-<meta name="generator"> מרגישה כמו הקשחה. תוקף מזהה את הגרסה שלך מתוך מחרוזות שאילתה של נכסים בתור, מתוך סימון block-editor, ומתוך תריסר סימנים נוספים תוך שניות. אתה לא מסתיר כלום; אתה רק גורם לעצמך להרגיש עסוק.

רשימות ענק של user-agent ו-referrer נגד בוטים. user agent הוא כותרת HTTP בודדת שקל לזייף. הרשימות האלה מיושנות ביום שאתה מדביק אותן, הן לא חוסמות שום דבר מוכשר, ו-Apache מעריך כל regex בכל בקשה — אתה משלם מס ביצועים אמיתי תמורת אפס אבטחה. דלג עליהן.

נעילת wp-login.php לפי IP. מצוין עד שספק האינטרנט שלך מחליף לך את הכתובת ונעלת את עצמך מחוץ לניהול שלך עצמך. ישים רק עם IP סטטי אמיתי.

הפניות נגד ספירת מחברים (?author=1). ה-rewrite ל-.htaccess שאנשים מדביקים לזה חלקי בפני עצמו — ה-endpoint של REST‏ /wp-json/wp/v2/users עדיין מציג שמות משתמש. חסימת נתיב אחד בזמן שהשני נשאר פתוח היא תיאטרון.

עדיין תקוע?

אם כלל מפיל את האתר ל-500, זה תחביר — הוצא את הבלוק האחרון שהוספת וטען מחדש; זה מבודד אותו מיד. אם נראה שכלל לא עושה כלום, ודא שאתה באמת על Apache ושה-AllowOverride מופעל עבור התיקייה (הרבה אחסונים מנוהלים מגבילים אותו). בנה את הקובץ מתבנית ידועה-טובה עם מחולל ה-.htaccess, שמור על שלושת הכללים שחשובים, וזרוק את השאר.