צ'קליסט אבטחה לוורדפרס: לתקן את הדברים המשעממים לפני שהם הופכים ליקרים
צ'קליסט אבטחה פרקטי לוורדפרס: משתמשים, סיסמאות, עדכונים, תוספים, .htaccess, ה-REST API, XML-RPC ו-WP-Cron.

רוב הפריצות לוורדפרס הן לא zero-days מגניבים, והן בטח לא מכוונות דווקא לאתר שלכם. רובן מתקפות אוטומטיות שמרוססות על אלפי אתרים. אצלכם פשוט במקרה הייתה דלת פתוחה.
חולשות ו-exploits בתוכנה מתועדים, מדורגים וממוינים בקפדנות. כל מי שיש לו תא מוח אחד יכול להוריד רשימת חולשות לגרסת וורדפרס, תוסף, תבנית או סקריפט מ-CDN, ואז לתת לבוט לסרוק את האינטרנט ולחפש מטרות מתאימות.
אל תבינו אותי לא נכון: יש מתקפות מגניבות עם הנדסה חברתית, zero-days אמיתיים, שרשראות אספקה, השתלטות על דומיינים, ועוד הרבה מונחים כיפיים. המאמר הזה לא עליהן. הוא על הדברים השגרתיים שקל לתקן ומשעמם לתחזק, ולכן מתעלמים מהם: תוסף ישן, סיסמה שממוחזרת, endpoint חשוף, או שרת שהוגדר עם כל הדלתות פתוחות כי ככה היה יותר מהר ביום שישי.
הצ’קליסט הזה הוא לא הבטחה לחסינות. זו דרך לצמצם את שטח התקיפה, לשים לב לצרות מוקדם יותר, ולהפוך את ההתאוששות להרבה פחות כואבת.
רוצים לראות קודם מה בוט רואה? בדיקת האבטחה לוורדפרס מסתכלת על האתר שלכם מבחוץ, על הדברים מהרשימה שרואים מהרחוב: שמות משתמש גלויים, XML-RPC, גרסה גלויה, HTTPS וכותרות. כל השאר זה שיעורי בית.
הגרסה הקצרה
אם יש לכם רק 30 דקות, עשו את אלה לפי הסדר:
- גבו הכל ותוודאו שאתם יודעים לשחזר אותו.
- עברו על כל החשבונות, מחקו את אלה שלא בשימוש ושימו לב במיוחד למנהלים.
- תנו לכל משתמש סיסמה ייחודית והפעילו 2FA למנהלים.
- עדכנו את וורדפרס, PHP, התבנית הפעילה וכל התוספים.
- מחקו תוספים ותבניות שלא בשימוש. קוד מושבת הוא עדיין קוד על השרת שלכם.
- התקינו תוסף אבטחה אחד והגדירו את ההתראות שלו.
- הוסיפו לוגים של פעילות ושל מיילים, כדי שתעלומות עתידיות ישאירו ראיות.
- בטלו את הצגת תוכן התיקיות והגנו על קבצים רגישים.
- הגבילו נתיבי REST API שאתם לא צריכים.
- בטלו את XML-RPC אם שום דבר לא משתמש בו.
- הגבילו או הסתירו את דף ההתחברות.
- החליפו את WP-Cron שמופעל על ידי מבקרים במשימה מתוזמנת אמיתית.
עכשיו בואו נעשה כל משימה כמו שצריך.
1. מתחילים בגיבוי
לפני שמשנים הגדרות אבטחה, גבו גם את מסד הנתונים וגם את הקבצים. גיבוי של wp-content בלבד הוא לא אתר שלם, וגם dump של מסד הנתונים בלי ה-uploads הוא לא.
שמרו לפחות עותק אחד הרחק מהשרת. אם השרת נפרץ, גיבוי שיושב על אותו שרת עלול להיעלם יחד איתו.
והכי חשוב, תדעו איך לשחזר אותו. גיבוי שלא נבדק הוא קובץ שנראה מלא תקווה, לא תוכנית התאוששות.
אם מסיבה כלשהי אי אפשר לגבות הכל, אני ממליץ קודם להסלים את הבעיה ולא לנסות להציל את האתר הזה לבד ובלי רשת ביטחון.
2. בודקים את המשתמשים
פתחו את משתמשים ← כל המשתמשים ותתחילו מהמנהלים.
- מחקו חשבונות ישנים של מפתחים, סוכנויות, עובדים וחשבונות זמניים.
- תנו לכל אדם חשבון משלו. חשבונות משותפים הופכים את לוג הפעילות לחסר תועלת.
- השתמשו בתפקיד הנמוך ביותר שמספיק לעבודה. רוב הכותבים צריכים Editor, לא Administrator.
- עברו על Application Passwords בפרופילי המשתמשים ובטלו את אלה שכבר לא שייכים לאינטגרציה פעילה.
- שנו שמות משתמש גנריים כמו
adminכשזה מעשי. זה מפחית רעש, אבל לא מחליף סיסמה טובה.
לכל מנהל שנשאר:
- צרו סיסמה ארוכה וייחודית עם מנהל סיסמאות.
- לעולם אל תמחזרו סיסמה מאתר אחר.
- הפעילו אימות דו-שלבי.
- ודאו שמייל איפוס הסיסמה מגיע לתיבה שהאדם הזה עדיין שולט בה.
תוקף שכבר נכנס לאתר יכול בקלות להסתיר חשבון מנהל מהרשימה הזו. אז אם יש ספק, אל תסמכו על לוח הבקרה ותשאלו את מסד הנתונים:
# WP-CLI, עם תוספים ותבניות כבויים כדי ששום דבר לא יסנן את הרשימהwp user list --skip-plugins --skip-themeswp db query "SELECT ID,user_login FROM wp_users"
# או MySQL רגיל: פרטי הגישה נמצאים ב-wp-config.php (או פשוט phpMyAdmin)mysql -h DB_HOST -u DB_USER -p DB_NAME -e "SELECT COUNT(*) FROM wp_users;"wp_ היא קידומת הטבלאות כברירת מחדל; הקידומת שלכם מופיעה ב-$table_prefix בתוך wp-config.php. אם המספר לא תואם למשתמשים ← כל המשתמשים, מישהו מתחבא.
3. מעדכנים הכל, ואז מנקים את השאריות
עדכנו את אלה ביחד:
- ליבת וורדפרס
- תוספים
- התבנית הפעילה
- PHP
- חבילות השרת, אם אתם מנהלים את השרת
קחו גיבוי קודם, עדכנו על staging אם האתר מכניס כסף, ואחר כך בדקו את החלקים שחשובים: התחברות, טפסים, checkout, מייל, חיפוש ואינטגרציות חיצוניות.
מחקו תוספים ותבניות שאתם לא משתמשים בהם. לא פעיל לא אומר לא נגיש. קבצי ה-PHP שלהם עדיין נמצאים מתחת ל-web root הציבורי, ועדיין אפשר לבקש קובץ פגיע ישירות.
השאירו תבנית ברירת מחדל עדכנית אחת של וורדפרס רק אם אתם רוצים אותה כגיבוי לשעת חירום. מחקו את ערימת התבניות הישנות שאף אחד לא זוכר שהתקין.
אל תשאירו תוכנה נטושה רק כי להחליף אותה זה לא נוח. אם תוסף כבר לא מתוחזק, אי הנוחות כבר הגיעה; היא פשוט מחכה לתאריך גרוע יותר.
4. מתקינים סט תוספים קטן ושימושי
יותר תוספי אבטחה לא אומר יותר אבטחה. שתי חומות אש שכותבות מחדש את אותם כללים בדרך כלל יוצרות בלבול, התראות כפולות ושבירות מוזרות. בחרו תוסף אבטחה ראשי אחד, תלמדו מה הוא עושה, ותגדירו אותו.
תוסף אבטחה אחד
Wordfence הוא אפשרות סבירה לשימוש כללי. הוא מספק חומת אש, סריקת נוזקות ושלמות קבצים, בקרת התחברות, אימות דו-שלבי והתראות אבטחה.
אחרי ההתקנה:
- הריצו את הסריקה הראשונה ובדקו את התוצאות.
- הפעילו אימות דו-שלבי למנהלים.
- הגדירו הגנה מפני brute-force.
- שלחו התראות לתיבת מייל שמישהו באמת קורא.
- אל תפעילו את כל האפשרויות האגרסיביות בבת אחת. שנו כמה הגדרות, ואז בדקו את האתר.
אם האחסון שלכם כבר מספק חומת אש מנוהלת לוורדפרס וסורק נוזקות, תבינו מה הוא מכסה לפני שאתם מוסיפים עוד תוסף כבד.
WP 2FA
WP 2FA מוסיף 2FA מבוסס מייל, למקרה שהקודים מאפליקציית האימות (TOTP) של Wordfence מסובכים מדי בשביל המשתמשים שלכם. האמת שאפשר לבנות כזה בעצמכם תוך כמה שעות, אבל תמיד יותר נוח שיש אחד שמוגדר ומתוחזק בשבילכם.
WP Activity Log
WP Activity Log מתעד אירועים שימושיים כמו התחברויות, שינויים במשתמשים, התקנות תוספים, שינויי הגדרות ועריכות תוכן.
הלוג עונה על השאלה שכל תקרית אבטחה מעלה בסוף: “מי שינה את זה, ומתי?” הגדירו זמן שמירה כדי שמסד הנתונים לא יגדל לנצח, והגבילו את הגישה ללוג לאנשים שבאמת צריכים אותה.
WP Mail Logging
WP Mail Logging מתעד הודעות שוורדפרס ניסה לשלוח. זה שימושי כשאיפוסי סיסמה, טפסי יצירת קשר או מיילים של הזמנות נעלמים בערפל.
לוגים של מיילים עלולים להכיל שמות, כתובות, תוכן הודעות וקישורי איפוס סיסמה. הגבילו מי יכול לקרוא אותם, שמרו אותם רק כל עוד הם שימושיים, ואל תתייחסו ללוג כהוכחה למסירה. הוא מוכיח שוורדפרס ניסה לשלוח את ההודעה. אם היא תגיע, זה כבר תלוי ב-SPF, DKIM ו-DMARC.
לא אבטחה, אבל כבר כשאתם שם
WP Rocket (caching) ו-WebP Express (תמונות קטנות יותר) לא יעצרו אף תוקף, אבל ל-WP Rocket מגיעים כמעט בכל התקנה בכל מקרה. קחו גם את ביטול ה-cache למנהלים אם אתם מתכננים לבדוק ב-production, ומכיוון ש-WebP Express מוסיף rewrite rules, בדקו את התמונות דרך ה-cache/CDN בחלון גלישה פרטי לפני שאתם מכריזים על ניצחון.
5. מקשיחים את Apache בלי לשבור את וורדפרס
הסעיף הזה מיועד לשרתי Apache או LiteSpeed שתומכים ב-.htaccess. Nginx לא קורא את הקובץ הזה; צרו כללים מקבילים בהגדרות השרת של Nginx במקום.
גבו קודם את ה-.htaccess הקיים. שימו כללים מותאמים מעל # BEGIN WordPress. וורדפרס עלול להחליף כל מה שנמצא בין סימוני ההתחלה והסוף שלו.
הוסיפו את זה ל-.htaccess בתיקיית השורש של וורדפרס:
# לא להציג רשימת קבצים כשבתיקייה אין קובץ index.Options -Indexes
# לחסום קבצים שאסור שאי פעם יורדו דרך שרת הווב.<FilesMatch "(?i)^(wp-config\.php|\.htaccess|\.htpasswd|debug\.log)$"> Require all denied</FilesMatch>
# לחסום קבצי גיבוי, הגדרות, לוגים ו-dump-ים נפוצים של מסד נתונים.<FilesMatch "(?i)\.(bak|conf|dist|ini|log|sh|sql|swp)$"> Require all denied</FilesMatch>אחר כך צרו .htaccess נפרד בתוך wp-content/uploads/:
# קבצים שהועלו לא אמורים לרוץ כ-PHP.<FilesMatch "(?i)\.(php[0-9]?|phtml|phar|phps)$"> Require all denied</FilesMatch>‹ apache 403. הגיבוי נשאר גיבוי, לא הורדה.
אחרי שמוסיפים את הכללים, בדקו את דף הבית, אזור הניהול, ספריית המדיה, הטפסים ועיבוד התמונות. 500 Internal Server Error אומר בדרך כלל שהאחסון לא מתיר אחת מההנחיות האלה. שחזרו את הגיבוי ובקשו מחברת האחסון את המקבילה ברמת השרת.
הוסיפו גם את זה ל-wp-config.php כדי להסיר מהלוח הבקרה את עורך הקוד המובנה של תוספים ותבניות:
define('DISALLOW_FILE_EDIT', true);זה לא יעצור מנהל שנפרץ מלהתקין תוסף זדוני, אבל זה מסיר דרך קלה אחת לערוך קבצים שרצים.
6. מגבילים את ה-REST API בזהירות
היכנסו לכתובות האלה כשאתם לא מחוברים:
https://example.com/wp-json/https://example.com/wp-json/wp/v2/usersהראשונה מציגה את כל נתיבי ה-REST הרשומים. השנייה עלולה לחלק שמות ו-slugs של כותבים. זו לא דליפת סיסמאות, אבל זה חוסך לבוטים שמנחשים סיסמאות חצי מהעבודה.
אבל אל תמחקו בתגובה את כל /wp-json/. עורך הבלוקים רץ עליו, וגם WooCommerce, Contact Form 7, Jetpack ורוב ההתקנות ה-headless.
לאתר תדמית פשוט בלי צרכני API ציבוריים, תוסף אבטחה מתוחזק יכול לדרוש אימות לבקשות REST אנונימיות. לאתר מורכב יותר, אפשרו את הנתיבים הציבוריים שה-frontend באמת משתמש בהם ודרשו אימות לכל השאר.
אחרי שמשנים את המדיניות, בדקו גם כשאתם מחוברים וגם כשלא:
- עמודים ופוסטים
- טפסי יצירת קשר
- חיפוש
- עמודי checkout וחשבון
- עורך הבלוקים
- אפליקציות מובייל, webhooks ואינטגרציות חיצוניות
המטרה היא לא “לגרום ל-/wp-json/ להחזיר שגיאה.” המטרה היא “לחשוף רק את הנתיבים שהאתר צריך.” וורדפרס עצמו ממליץ לא לבטל את ה-REST API לגמרי.
7. מבטלים את XML-RPC כששום דבר לא צריך אותו
XML-RPC הוא ה-API המרוחק שהיה לוורדפרס לפני ה-REST API. היום הוא משרת בעיקר את Jetpack, חלק מתהליכי העבודה של אפליקציות מובייל, pingbacks, ובוטים של brute-force שאוהבים אותו כי בקשה אחת יכולה לסחוב מאות ניחושי סיסמה. אם אתם לא משתמשים באף אחד מהשימושים הלגיטימיים, חסמו אותו ברמת שרת הווב כדי שוורדפרס אפילו לא יתעורר בשבילו.
‹ xmlrpc 500 ניחושים, בקשה אחת. המגביל ספר 1.
הוסיפו את זה ל-.htaccess שבשורש, מעל הסימונים של וורדפרס:
<Files "xmlrpc.php"> Require all denied</Files>אחר כך היכנסו ל-https://example.com/xmlrpc.php. אתם אמורים לקבל 403 Forbidden, ולא את ההודעה הרגילה “XML-RPC server accepts POST requests only”.
אם Jetpack או אינטגרציה אחרת מפסיקים לעבוד, החזירו את הגישה והשתמשו בתוסף האבטחה כדי לבטל רק את האימות של XML-RPC או את ה-pingbacks.
8. מגבילים או מסתירים את דף ההתחברות
חסימת XML-RPC, הפעלת 2FA ושינוי כתובת ההתחברות הם הרגלים טובים. אבל הפתרון הכי טוב הוא פשוט לתת רק לכתובות IP מוכרות להגיע ל-wp-login.php ול-/wp-admin/, עם רשימת IP מורשים או Tailscale. ככה, גם אם התוקף יודע את פרטי ההתחברות שלכם או אפילו מחזיק בעוגיית הסשן, הוא לא יוכל להשתמש בהם כדי להתחבר או לשנות את האתר.
זה די קל לעשות. ב-Apache זה כמה שורות של Require ip, יש הרבה מדריכים, וכנראה אוסיף מדריך משלי בעתיד. השאירו את /wp-admin/admin-ajax.php פתוח: טפסים, עגלות קניות וחיפוש באתר הציבורי קוראים לו לא מעט.
9. מחליפים את WP-Cron; לא סתם מכבים אותו
WP-Cron הוא בכלל לא באמת cron. וורדפרס בודק אם הגיע הזמן להריץ משימות בכל פעם שמישהו טוען עמוד, אז באתר שקט הפוסט המתוזמן שלכם יוצא מתי שהמבקר הבא ישוטט פנימה, ובאתר עמוס זו בדיקה נוספת שמוברגת לכל בקשה. תנו את העבודה למתזמן האמיתי של השרת.
‹ wp-cron הפוסט של 09:00 יצא ב-11:42. תודה למבקר הראשון.
קודם הוסיפו את זה ל-wp-config.php:
define('DISABLE_WP_CRON', true);אחר כך הריצו את האירועים שהגיע זמנם כל חמש דקות עם cron job אמיתי. אם WP-CLI מותקן, זו הגרסה הכי נקייה:
*/5 * * * * cd /path/to/wordpress && /usr/local/bin/wp cron event run --due-now --quietהשתמשו בנתיב הנכון של וורדפרס ושל WP-CLI בשרת שלכם, והריצו את המשימה כבעלים של האתר ולא כ-root. ברוב פאנלי האחסון יש מסך Cron Jobs או Scheduled Tasks שבו אפשר להוסיף את אותה פקודה. כדי לבדוק מתי התזמון באמת רץ לפני שסומכים עליו, הדביקו אותו במפענח ה-cron.
רק אחרי שהמשימה הזאת עובדת, חסמו גישה ציבורית ל-wp-cron.php:
<Files "wp-cron.php"> Require all denied</Files>בדקו את זה עם:
wp cron event listאם פוסטים מתוזמנים, גיבויים, משימות ניקוי או פעולות של WooCommerce מפסיקים לרוץ בשקט, ה-cron החלופי שלכם לא עובד. הסירו את DISABLE_WP_CRON עד שזה יתוקן. cron שבור לא זורק שגיאות; הוא פשוט מפסיק לעשות דברים, ואתם שמים לב אחרי כמה שבועות. מדריך התוספים של וורדפרס מתאר את אותו תהליך החלפה.
שומרים על תחזוקה
אבטחה היא בעיקר תחזוקה עם השלכות טובות יותר.
כל שבוע: עברו על עדכונים קריטיים והתראות אבטחה, ואז ודאו שהגיבויים הושלמו.
כל חודש: עדכנו הכל, עברו על המנהלים ועל ה-application passwords, בדקו את לוג הפעילות, ומחקו קוד שלא בשימוש.
כל כמה חודשים: שחזרו גיבוי למקום בטוח ובדקו אותו. ודאו שטפסים, מייל, cron jobs ואינטגרציות חיצוניות עדיין עובדים.
אם האתר נפרץ, אל תמחקו סתם את הקובץ החשוד ותמשיכו הלאה. שמרו את הלוגים, החליפו פרטי גישה, מצאו את נקודת הכניסה, תקנו אותה, חפשו מנגנוני persistence, ושחזרו מגיבוי שידוע שהוא תקין כשצריך.
מקורות שימושיים
- מדריך ההקשחה של וורדפרס
- מדריך ה-REST API של וורדפרס
- הנחיות Apache ו-
.htaccessלוורדפרס - הרשאות קבצים בוורדפרס
תמונת שער: מנעולים עתיקים, מוזיאון אוצרות בחומה, עכו, צילום: Adam Jones, CC BY-SA 2.0.
תגובות
התגובות נשמרות ב-GitHub Discussions (דרך giscus), אז כדי להצטרף לשיחה צריך חשבון GitHub.