כשגלישה ל-https://example.com/wp-content/uploads/ מחזירה רשימה של תיקיות וקבצים – זוהי תכונה של השרת בשם directory listing שמופעלת כברירת מחדל בכמה תצורות ישנות של Apache. אתר WordPress תקין צריך להחזיר 403 או דף ריק. רשימה גלויה היא חשיפת מידע שמסכנת את האתר גם אם הקבצים עצמם "לא רגישים" לכאורה.
למה זה משנה
תיקיית uploads לרוב מכילה הרבה יותר ממה שעולה לדעת: גיבויי מסד שתוסף backup לא הצליח להעלות לחיצוני וזרק לתיקייה זו, מסמכי PDF פנימיים שהועלו זמנית, סרטוני training של עובדים, תמונות שהוסרו מפוסט אבל נשארו על הדיסק, וקבצי .htaccess שתוסף שגוי כתב ב-uploads. תוקף שמסתכל על הרשימה רואה את כל זה. דוגמה אמיתית: בלוגים רבים נחשפו במאסה גלובלית כשתוסף UpdraftPlus כתב לתיקיית uploads גיבוי ZIP מלא של DB וקבצים – ושמו של ה-ZIP היה ניחושי. תוקף שגלש לתיקייה ראה את הגיבוי, הוריד אותו וקיבל את כל האתר. גם בלי גיבויים, חשיפת רשימת תוספים פעילים (דרך שמות תיקיות ב-plugins/) מאפשרת לתוקף לבחור פרצה ספציפית לכל תוסף.
איך לזהות
במצב גלישה פרטית, גש ל:
https://example.com/wp-content/uploads/https://example.com/wp-content/uploads/2024/https://example.com/wp-content/plugins/https://example.com/wp-includes/
אם רואים כותרת "Index of /..." או רשימת קבצים – directory listing פעיל. צריך לקבל 403 או redirect לעמוד הבית.
איך לתקן
ב-Apache, הוסף ל-.htaccess בשורש האתר:
Options -Indexes
זו הוראה אחת שמכבה את התכונה לכל התיקיות הוויראליות. אם רוצים לעשות זאת רק ל-uploads:
# wp-content/uploads/.htaccess
Options -Indexes
<FilesMatch "\.(zip|sql|gz|tar|bak)$">
Require all denied
</FilesMatch>
ב-Nginx, ב-server block:
autoindex off;
location ~* \.(zip|sql|gz|tar|bak)$ {
deny all;
return 404;
}
שכבה משלימה – הוסף קובץ index.php ריק בכל תיקייה. אם directory listing יופעל בטעות, הדפדפן יקבל את הקובץ הריק במקום הרשימה:
<?php
// Silence is golden.
WordPress יוצר את הקובץ הזה אוטומטית בתיקיות הראשיות של uploads, אבל לא בכל ה-subfolders שנוצרים לפי שנה/חודש. הוסף ידנית או דרך סקריפט: find wp-content/uploads -type d -exec touch {}/index.php \;
טעויות נפוצות
טעות ראשונה: לחסום את /wp-content/uploads/ לחלוטין במקום רק את ה-listing. זה יחסום גם תמונות לגיטימיות וישבור את האתר. Options -Indexes מבטל רק את הצגת הרשימה ולא את הגישה לקבצים בודדים. טעות שנייה: לסמוך על שמות קבצים אקראיים. backup-1d8f2k3.zip אולי לא ניתן לניחוש, אבל אם הוא מופיע ברשימה ציבורית – ה-randomness לא עוזרת. טעות שלישית: לטפל רק ב-Apache ולשכוח את ה-Nginx שלפניו (או להפך). אם ה-Nginx משמש כ-reverse proxy ל-Apache, ה-listing עלול להיות חסום באחד ופתוח באחר.
בדיקה לאחר תיקון
חזור על אותן בדיקות מהשלב "איך לזהות". כל ארבעת ה-URL-ים אמורים להחזיר 403, 404 או דף ריק – לא רשימת קבצים. בדיקה אגרסיבית יותר עם curl: curl -s https://example.com/wp-content/uploads/ | head -20 – אם הפלט ריק או 403, החסימה עובדת. בנוסף, חפש קבצים שהועלו בטעות: find wp-content/uploads -name "*.zip" -o -name "*.sql" -o -name "*.bak" ומחק אותם.