צ'קליסט התקשחות לאתר חדש

רשימת בדיקה למפתח שמקים אתר WIZZO CMS: מפתחות הצפנה, הרשאות קבצים, כתובת הניהול, HTTPS, כותרות אבטחה, גיבויים ומה לכבות לפני עלייה לאוויר.

⏱ 6 דק' קריאה 1066 מילים ערוך דף זה ב-GitHub

הליבה מגיעה עם ברירות מחדל שנוחות לפיתוח ולא בטוחות לייצור. הצ'קליסט הזה עובר על כל מה שמפתח אתר צריך לסגור לפני שהאתר עולה לאוויר, לפי סדר חשיבות. הסעיף הראשון קריטי: בלעדיו שאר ההגנות אינן שוות הרבה. ההסבר למה כל סעיף נחוץ נמצא במודל האבטחה.

system/ בעמוד הזה הוא תיקיית הליבה הפרוסה (api/core בריפו), ו-{admin} הוא CONFIG::$admin_url. קטעי הגדרות השרת (apacheconf) הם המלצות להתאמה: הריפו של הליבה אינו כולל קובץ .htaccess של שורש האתר, והם כתובים כך שיעבדו בשרת Apache עם mod_headers.

1. מפתחות הצפנה: חובה#

מפתחות ברירת המחדל הם סוד גלוי
MISC::encode משתמש במפתח ו-IV קבועים בקוד, ו-CRYPT במפתח 'wizzocms'. אתר שלא מחליף אותם מאפשר לכל מי שקרא את קוד הליבה לזייף עוגיות התחברות, טוקנים וקישורי מייל, ואף להזריק אובייקטים דרך unserialize (ממצאים SEC-02 ו-CORE-01). זה הצעד הראשון בכל אתר חדש, לפני שהמשתמש הראשון נרשם.

ב-application/includes/init.php (נטען בכל בקשה, גם CLI ו-cron):

<?php
$keys = require CONFIG::$base_path . "/../secrets/wizzo_keys.php";   // מחוץ ל-docroot

MISC::set_encrypt_secret_keys($keys["key"], $keys["iv"]);
CRYPT::set_secret_key($keys["crypt"]);
  • שלושה ערכים אקראיים שונים, באורך 32 בתים לפחות (openssl rand -hex 32), ייחודיים לכל אתר ולכל סביבה.
  • הערכים לא נכנסים ל-git. ראו הצפנה למה אסור לסובב אותם אחרי שיש נתונים: כל עוגייה, טוקן וקישור קיים יפסיקו לעבוד.
  • בדיקה שזה עבד: טוקן שנוצר ב-MISC::encode("x") באתר שלכם שונה מזה שנוצר באתר אחר, ופענוח של טוקן מאתר אחר מחזיר false.

2. קבצים שלא יוצאים ל-HTTP#

קובץהסיכוןמה עושים
config.php (מחלקת CONFIG_USER: פרטי DB, SMTP, FTP)סיסמאות בטקסט גלוימחוץ ל-docroot, או לפחות חסום (ראו system/.htaccess למטה)
system/market_settings.json, system/*_key.json, system/system_tags.jsonמפתחות שירותחסומים אוטומטית על ידי הליבה
sqllog.txt בשורש האתרכל שאילתות ה-SQL, כולל נתוניםlog_sql כבוי בייצור; הקובץ חסום או נמחק
גיבויים, dump-ים, .env, .gitקוד וסודותלא בתוך ה-docroot, או חסומים

הליבה מנסה לשתול system/.htaccess עם <FilesMatch> שחוסם market_settings.json*, system_tags.json, config.php, קבצי *_key.json / *_keys.json וקבצים שמתחילים בנקודה (market_service::protect_settings_dir()). זו רשת ביטחון ולא תחליף: ודאו בפועל שהקובץ קיים ושבקשת HTTP לאחד הקבצים האלה מחזירה 403.

curl -s -o /dev/null -w "%{http_code}\n" https://example.co.il/system/market_settings.json
curl -s -o /dev/null -w "%{http_code}\n" https://example.co.il/sqllog.txt

ביומן SQL: הפרמטר log_sql ב-CRM_params שווה 1 כשהוא פעיל. בדיקה:

SELECT value FROM CRM_params WHERE sysName = 'log_sql';

3. הרשאות קבצים#

FILES::make_dir() יוצר תיקיות (למשל media/Storage) במצב 0777 ובמסכה מאופסת, כלומר פתוחות לכתיבה לכל משתמש במכונה. בשרת משותף זה לא מקובל.

  • הקוד (system/, application/) קריא על ידי משתמש ה-web ולא ניתן לכתיבה על ידו, חוץ ממה שחייב להיכתב.
  • ניתנים לכתיבה רק התיקיות שהאתר באמת כותב אליהן: cache/, media/ (העלאות) ותיקיית הגיבויים אם יש. אחרי שה-STORAGE יצר תיקייה, כווצו אותה:
find media -type d -exec chmod 755 {} \;
find media -type f -exec chmod 644 {} \;
  • בתיקיות ההעלאה אסור להריץ קוד. גם אם קובץ זדוני עבר את החסימה של STORAGE (שהיא רשימה שחורה, ראו אבטחת העלאות), הוא לא אמור להתבצע:
# media/.htaccess
<FilesMatch "\.(php|phtml|phar|pl|py|cgi|sh)$">
    Require all denied
</FilesMatch>
Options -ExecCGI
RemoveHandler .php .phtml

4. כתובת הניהול ושער המדינות#

  • CONFIG_USER::$admin_url הוא ה-slug של הפאנל (ברירת המחדל בדוגמאות היא wizzocms). שינוי ל-slug לא צפוי מוריד רעש של סורקים אוטומטיים, אבל הוא לא אמצעי הגנה: ההגנה האמיתית היא ההתחברות. אל תעבדו עם הבנה שהכתובת "סודית".
  • אם כל מנהלי האתר בארץ אחת, CONFIG_USER::$admin_countries = ["IL"]; חוסם גישה לפאנל מ-IP של מדינות אחרות. שער המדינות מבוסס על כתובת ה-IP של המבקר, ולכן הוא מסנן רעש ולא אמצעי אימות.

5. HTTPS#

  • האתר מוגש ב-HTTPS בלבד, עם הפניה מ-HTTP ברמת השרת.
  • הליבה קובעת CONFIG::$protocol לפי $_SERVER["HTTPS"] == "on" בלבד. כשה-TLS מסתיים בפרוקסי (Cloudflare, load balancer), ודאו שהשרת מעביר את HTTPS=on ל-PHP, אחרת קישורים שהליבה בונה ייצאו עם http://.
  • עוגיות הליבה נשלחות עם Secure, ולכן בלי HTTPS הן פשוט לא יישמרו.

6. כותרות אבטחה#

הליבה לא שולחת Content-Security-Policy, X-Frame-Options, Strict-Transport-Security או Referrer-Policy. מוסיפים בשרת:

<IfModule mod_headers.c>
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>

Content-Security-Policy תלוי בסקריפטים של האתר (אנליטיקס, תגיות, CKEditor בפאנל) ולכן מתחילים ב-Content-Security-Policy-Report-Only, בודקים, ורק אחר כך אוכפים. אם מוסיפים HSTS עם includeSubDomains, ודאו שכל תתי-הדומיינים כבר ב-HTTPS.

7. סיסמאות משתמשי האתר#

LOGIN::$encryption ברירת המחדל היא md5, שאינה מתאימה לשמירת סיסמאות. בחרו bcrypt ב-init.php, לפני שנרשם המשתמש הראשון:

LOGIN::$encryption = "bcrypt";

סיסמאות שנשמרו כבר ב-md5 לא יתאימו אחרי המעבר. תכננו מראש. פרטים ב-משתמשי אתר.

8. מה לכבות או להגביל#

  • פאנלים רגישים לקבוצת המפתחים בלבד. file_manager נרשם עם perm_developer=1. db_manager נרשם על ידי install_db_manager.php עם perm_developer=0, כלומר גלוי לכל מי שיש לו הרשאה לפאנל לפי קבוצתו. אחרי ההתקנה:
UPDATE CRM_adminPanel_panels SET perm_developer = 1 WHERE panel_name IN ('db_manager', 'file_manager', 'composer');

(בדקו קודם SELECT panel_name, perm_developer FROM CRM_adminPanel_panels; השם composer תלוי בהתקנה.)

  • תצוגת שגיאות כבויה. display_errors=0 ב-php.ini של הייצור; שגיאות הולכות ליומן, לא למסך.
  • משימות cron מיותרות. בפאנל {admin}/cron_manager השאירו רק משימות שהאתר צריך. ראו cron.
  • נקודות /system/* שאתם לא משתמשים בהן (למשל ai_cron, אם אינכם מפעילים כלי AI מתוזמנים) אפשר לחסום בשרת, כי כל קובץ בקר מערכת נגיש ציבורית כל עוד הוא קיים.
  • שירותים שלא בשימוש. טוקני MCP שפג הצורך בהם נמחקים; אל תשאירו טוקן פעיל "ליתר ביטחון".
  • mail_queue. אם הפעלתם CONFIG_USER::$mail_queue, שימו לב שהנקודה /system/Tools/cron_emails_queue ציבורית. ראו מייל.

9. גיבויים#

  • מה מגבים: בסיס הנתונים (כל טבלאות CRM_*), תיקיית ההעלאות (media/), application/, ו-config.php עם הערכים של המפתחות (בנפרד ומוצפן).
  • איפה: מחוץ ל-docroot ומחוץ לשרת עצמו. גיבוי שנמצא באותה תיקייה שמוגשת ב-HTTP הוא דליפה.
  • בודקים שחזור, לא רק יצירה. גיבוי שמעולם לא שוחזר אינו גיבוי.
  • שימו לב לגודל: גיבוי מקומי שממלא את הדיסק מפיל את האתר.

10. בדיקת סיום לפני העלייה#

  • MISC::set_encrypt_secret_keys ו-CRYPT::set_secret_key נקראים עם ערכים ייחודיים.
  • config.php, sqllog.txt ו-market_settings.json מחזירים 403 או 404 מבחוץ.
  • log_sql כבוי, display_errors כבוי.
  • HTTPS מלא, והליבה בונה קישורים עם https://.
  • כותרות האבטחה מופיעות (בדיקה עם curl -I).
  • LOGIN::$encryption = "bcrypt" (אם יש משתמשי אתר).
  • db_manager ו-file_manager מוגבלים למפתחים.
  • בתיקיית ההעלאות לא מורצים קבצי PHP.
  • יש גיבוי, ושוחזר פעם אחת בהצלחה.

ראו גם#

מצאתם טעות או חוסר? תקנו את הדף או פתחו Issue בריפו. התיעוד נכתב מתוך הקוד של ליבה 5.0.115.