התחברות, סשנים ו-WIZZO ID

איך מנהל נכנס לפאנל הניהול: טופס ההתחברות, נעילת ניסיונות, אימות דו-שלבי דרך WIZZO ID, טבלת adminPanel_sessions, התחברות כמנהל אחר (login_as) והתנתקות.

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

התחברות לפאנל הניהול מורכבת מסיסמה (bcrypt), מאימות דו-שלבי אופציונלי (WIZZO ID או קוד במייל/SMS) וסשן מבוסס טוקן שנשמר בטבלה. בדף הזה מוסבר מה קורה בכל שלב, מה נשמר איפה, ואיך מנהל מפתח נכנס בשם מנהל אחר. כל הפונקציות הן מתודות סטטיות של המחלקה ADMIN (system/collections/ADMIN.php) והקונטרולר system/admin_login.

{admin} בדף הוא CONFIG::$admin_url, ו-system/ הוא תיקיית הליבה (api/core בריפו).

זרימת ההתחברות#

כשמבקר שאינו מחובר נכנס לכתובת {admin}, PAGE::load בוחר את ה-theme admin_login במקום admin_panel. הטופס שולח POST אל system/admin_login?action=login.

  1. בדיקת מקור: הקונטרולר בודק שה-host של ה-Referer תואם לאתר.
  2. CSRF (double submit): הטופס נושא טוקן שמקורו בעוגייה admin_csrf. ADMIN::generate_csrf_cookie() יוצרת אותה (32 בתים אקראיים בהקסדצימלי, תוקף שעה) או מחזירה את הקיימת, ו-ADMIN::verify_csrf_token($posted) משווה עם hash_equals ומחזירה false אם אחד הערכים ריק.
  3. בדיקת פרטים: ADMIN::check_details($username, $password, $phone = false, $record_bad_attempt = true) מאמתת את הסיסמה מול ה-hash (bcrypt).
  4. אימות שני: לפי הגדרות המנהל (ראו להלן).
  5. יצירת סשן: ADMIN::admin_log(...) יוצרת שורה ב-CRM_adminPanel_sessions ומציבה עוגיות.

נעילה אחרי ניסיונות כושלים#

check_details סופרת ניסיונות כושלים מהטבלה adminPanel_admins_bad_attempts. אחרי 5 ניסיונות לכל משתמש ב-10 דקות, או 15 לכל כתובת IP, היא מחזירה "to_many_ettempts" (כך מאויית הערך בקוד) ולא בודקת את הסיסמה. למנהל אפשר להגדיר גם רשימת allow_ip (שדה מוצפן ב-MISC::encode); כניסה מכתובת שלא ברשימה נדחית.

הערה

הרשימה allow_ip נערכת בטופס המנהל בשדה Tags. מנהל ללא רשימה יכול להתחבר מכל כתובת.

אימות דו-שלבי#

הגדרת המנהל (CRM_adminPanel_admins) קובעת מה קורה אחרי סיסמה נכונה:

מצבהתנהגות
skip_otp = 1כניסה מיידית, בלי שלב שני
WIZZO ID זמיןwizzo_auth::send שולחת בקשה ל-https://auth.wizzo.co.il/api/send_otp ומקבלת טוקן. הטוקן חוזר לדפדפן בכותרות otp_token ו-otp_push, והדפדפן ממתין לאישור בטלפון של המנהל
WIZZO ID לא זמיןקוד בן 4 ספרות נשלח במייל (או ב-SMS דרך המודל m_sms). ה-hash של הקוד נשמר ב-phone_last_code ותאריך השליחה ב-phone_last_code_date; שליחה חוזרת אפשרית רק אחרי 3 דקות

ההמתנה לאישור WIZZO ID היא long-poll: כל קריאה ל-check_otp ממתינה עד 25 שניות מול השרת, וכל בקשה בדפדפן עד כ-50 שניות. התשובה היא true (אושר), declined (נדחה) או false (עדיין ממתין). באישור, הטוקן של המפתח (developer_token) נשמר במנהל ונקראת admin_log. את הקוד שנשלח במייל או ב-SMS מאמתים ב-system/admin_login?action=phone.

סשנים: הטבלה adminPanel_sessions#

כל התחברות מוצלחת יוצרת שורה בטבלה CRM_adminPanel_sessions. הטבלה נוצרת אוטומטית (ensure_sessions_table()) אם היא חסרה.

עמודהמשמעות
idמפתח
admin_idהמנהל
tokenbin2hex(random_bytes(32)), הערך שבעוגייה
ip, user_agent, device_labelפרטי המכשיר, להצגה במסך "ההתחברויות שלי"
created_at, last_active_at, expires_atמחזור החיים
is_impersonated, impersonated_byסשן של "התחבר כמנהל" (ראו להלן)

עוגיות#

עוגייהתפקיד
admin_sessionהטוקן. נקבעת עם COOKIES::set_secure, 168 שעות (שבוע), HttpOnly, Secure, SameSite=Lax
admin_loggedדגל שה-JavaScript יכול לקרוא (בלי הטוקן עצמו)
admin_csrfטוקן ה-CSRF (double submit) של טופס ההתחברות; פאנלים כמו file_manager משתמשים בו גם לפעולות כתיבה שלהם

בכל בקשה ADMIN::get_id() מאתרת את הסשן לפי העוגייה. היא מאריכה את expires_at ו-last_active_at לכל היותר פעם ב-5 דקות, כדי לא לכתוב לבסיס הנתונים בכל בקשה. עוגיית admin_token ישנה (מהמנגנון הקודם) מועברת אוטומטית לסשן חדש.

פונקציות ניהול סשנים#

פונקציהמה עושה
ADMIN::admin_logout()מוחקת את שורת הסשן ואת העוגיות. נקראת גם דרך GET system/admin_login/logout
ADMIN::logout_all()מנתקת את כל הסשנים של המנהל
ADMIN::get_active_sessions()רשימת הסשנים הפעילים של המנהל הנוכחי
ADMIN::get_current_session_id()מזהה הסשן הנוכחי
ADMIN::revoke_session($id)מבטלת סשן אחד
ADMIN::invalidate_sessions_on_password_change(...)מבטלת סשנים אחרי החלפת סיסמה
ADMIN::cleanup_expired_sessions()מוחקת סשנים שפג תוקפם

ניקוי הסשנים שפג תוקפם רץ מדי יום ב-03:00 דרך הקונטרולר admin_session_cleanup/run (cron 0 3 * * *).

בפאנל Admins שלושה עמודי POST מנהליים: my_sessions, revoke_session ו-logout_all_sessions. השניים האחרונים מקבלים session_id ב-POST ומחזירים ok.

שימו לב
logout ו-ניקוי המטמון (clear_cache) מתבצעים גם ב-GET, ולכן קישור או תמונה בדף זר יכולים להפעיל אותם. אל תוסיפו פעולות משנות מצב על GET בפאנלים שלכם.

התחברות כמנהל אחר (login_as)#

מפתח שמתחבר עם WIZZO ID יכול להיכנס בשם מנהל אחר כדי לשחזר בעיה. הכפתור "התחבר כמנהל" ברשימת Admins מוצג רק כש-ADMIN::is_developer() נכון, ולא עבור המשתמש עצמו.

  1. ADMIN::create_login_as_token(...) מייצרת מטען (target_id, requester_id, זמן וערך אקראי) מוצפן ב-MISC::encode.
  2. הקישור הוא {site_url}/system/admin_login/login_as?token=....
  3. validate_login_as_token מקבלת טוקן בן 60 שניות לכל היותר.
  4. הקונטרולר דורש שלמבקש יהיה developer_token לא ריק.
  5. ADMIN::admin_log_impersonate(...) יוצרת סשן עם is_impersonated = 1, impersonated_by שמצביע על המפתח, ו-device_label שמסתיים ב-(impersonated).
הערה

כל סשן "כמנהל" נשמר בטבלה עם מי שביצע אותו, ולכן אפשר לשאול בכל רגע מי נכנס בשם מי: SELECT admin_id, impersonated_by, created_at FROM CRM_adminPanel_sessions WHERE is_impersonated = 1.

מפתחים וטוקן המפתח#

ADMIN::is_developer() נקבעת פעם אחת בכל בקשה. היא קוראת את developer_token של המנהל ומאמתת אותו ב-decode_developer_token: חתימת RSA-SHA256 על ההודעה dev|user_id|time מול המפתח הציבורי של WIZZO ID (קבוע ב-ADMIN.php). בלי openssl האימות נכשל (fail closed), כלומר אף אחד לא נחשב מפתח.

טוקן שפג תוקפו מחודש ב-wizzo_auth::renew_developer_token (קריאה ל-auth.wizzo.co.il/api/renew_developer_token, timeout של 10 שניות). אם השרת דוחה את החידוש, הטוקן נמחק; אם אין תשובה (תקלת רשת), הטוקן נשמר.

מי נחשב מפתח משפיע על: פאנלים שסומנו perm_developer, הכפתור login_as, וסוגי פאנלים כמו composer ו-file_manager (ראו הרשאות).

אזהרה

המפתח הציבורי של WIZZO ID הוא קבוע בקוד הליבה ואסור לשנות אותו באתר: הוא מה שמבדיל בין מפתח אמיתי למי שמזייף טוקן. ההצפנה של MISC::encode (המשמשת את טוקן login_as ואת רשימת ה-IP) מתבססת על מפתח ברירת מחדל שחייבים להחליף לכל אתר עם MISC::set_encrypt_secret_keys (ראו הקשחה).

ראו גם#

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