הליבה מגיעה עם ברירות מחדל שנוחות לפיתוח ולא בטוחות לייצור. הצ'קליסט הזה עובר על כל מה שמפתח אתר צריך לסגור לפני שהאתר עולה לאוויר, לפי סדר חשיבות. הסעיף הראשון קריטי: בלעדיו שאר ההגנות אינן שוות הרבה. ההסבר למה כל סעיף נחוץ נמצא במודל האבטחה.
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.
- יש גיבוי, ושוחזר פעם אחת בהצלחה.