@avi-rz
מיותר החסימה, אתה לא צריך לעשות שום דבר מקורי.
אמנם אתה כן צריך לחייב סיסמה ארוכה וקשה (ואם זה מאוד רגיש ויש מקום לחשש אז לחייב Two Factor).
שים לב בexpress-session מקבל secret, שים שמה משהו רנדומלי.
ראה גם הערה בהמשך לגבי גיבוב הסיסמה - זה לא מוסיף אבטחה על האתר אלא מגן על סיסמת המשתמש.
עד כאן זה הטכניקה, וכפי שאתה רואה אין פה כמעט כלום. אז איך כל הזמן יש פריצות לאתרים? בגלל לוגיקה שגויה של מפתח, ודי במקום אחד לאורך כל היישום.
יש כמה סוגים עיקריים, אני שם לפי סדר התדירות לדעתי:
א. חוסר ביקורתיות על קלט משתמש. זה כולל כמה וכמה התקפות, אני ארחיב בהמשך.
ב. חוסר התבוננות על השלכות של פעולות, שמאפשרות למשתמש בהינתן מצבים מסויימים למצל אותם.
ג. מימוש בדיקת אבטחה בצורה לקויה או באופן לא מספק.
ד. טעויות של ממש ובאגים, שמשתמש הצליח לקלוט ולנצל.
בארץ יש הרבה מהכל כולל גם מהשלישי, למרות שאמור להיות נדיר מאוד.
עיקר הבעיה בכל הסעיפים, שהם לא מלווים את המפתח כשהוא עוסק בחלק האבטחה של היישום שלך, אלא כל הזמן וממילא המודעות שלו יותר נתונה לבעייה X כמו "איך לסדר שחשבונית לא תיצא לפני הקבלה", ופחות לבעיות אבטחה שהוא יוצר.
דוגמאות:
א. חוסר ביקורתיות על קלט משתמש
זו הבעיה מספר 1 שאין מצב להינצל ממנה בלי אימון של חשיבה ביקורתית.
- sql injection קלאסי (שרשור טקסט) ופחות קלאסי שזה קצת הסעיף הבא).
- קלטים לא צפויים במבט של מפתח נחמד, אלא רק עם ביקורת קצת קרימינלית:
למשל אתה מצפה לקבל מספר שלם בין 1 ל10, ואפילו מוודא את זה עם פונקציה, ואתה גם מוודא שלא מדובר ב5 כי זה צריך הרשאה משמעותית יותר. אבל המשתמש החכם שם 4.9 שזה לא 5... בהכנסה למסד זה מתעגל ל5 - מספר שלם בגלל איזה ספריה כשרונית כל שהיא שמתאימה את הקלט לשדה שהוא מסוג מספר שלם.
דוגמה גרועה יותר זו בדיקה טקסטואלית על קלט שבסוף מספרי אפליקטיבית - param != '5', ואז המשתמש שולח לך 5.0 או 05...
- קלטים קיצוניים שגורמים לבאג/שגיאה שמבחינה לוגית מביאה למשתמש ייתרון שלא אפשרת לו בcontrole flow. למשל שמת try אבל הקוד ממשיך אח"כ, בלי החלק האבטחתי שבתוך הtry (זה לא קשור לקלט משתמש דוקא, כי יש עיקרון: כל try עיוור, שמאפשר להכיל כל שגיאה, הוא פוטנציאלית בעיית אפליקציה ולעיתים בעיית אבטחה. לא לעשות try-catch בלי שיודעים מה תהיה השגיאה).
למשל אתה מקבל מייל ומוודא עליו משהו, אבל לא חשבת שיכול להיות שהמשתמש ישלח מחרוזת באורך של מגה... אבל לא היה קורה כלום אם לא שבעודף תבונה שמו try שמה על משהו, ובחוסר תבונה לא דאגו שכל catch לא צפוי יזרוק שוב שגיאה (כל המפתחים כמעט כולל עבדך הנאמן מוותרים על הרעיון...) הקוד בהמשך הוא יכול להיכשל (הכי טוב) ואולי להשאיר תוצאות לא רצויות (פחות טוב) ולפעמים לאפשר משהו שלא רצינו (פירצת אבטחה).
ב. חוסר התבוננות על השלכות של פעולות שאפשרו למשתמש לבצע
ככלל, כל דבר שלא מצליחים להתרכז (מחוסר כח/זמן/ריכוז) ולחפש את ההשפעות המלאות שלו לא לאפשר, ודאי לא למשתמש עם הרשאה נמוכה.
הדוגמאות הבאות חלשות, אני פשוט בדיוק לא מצליח כעת להיזכר דברים שיצא לי להיכשל בהם או לראות אחרים שנכשלים שהם עסיסיים בהרבה...
- לאפשר למשתמש לשנות כתובת מייל בלי לחשוב על השלכות אבטחה, למשל כתובת קיימת למשתמש אחר, או פישינג מוצלח כאשר יש לו השפעה על לינק או תוכן שנשלח במייל בשם האתר.
- לאפשר למנהל למחוק משתמשים בלי לוודא שהוא לא מוחק מנהל ברמה גבוהה ממנו.
ג. מימוש בדיקת אבטחה בצורה לקויה או באופן לא מספק.
- ניסיון מימוש אבטחה מקורי/אישי, כשמדובר במקרה קלאסי ובפרט סבוך.
למשל טיהור קלט פרמטרי SQL על ידי החלפות או עטיפה במרכאות וכדומה, במקום טכניקה של פרמטרים.
טיהור HTML עם regex וכדומה, במקום שימוש בספריה עם שימוש מסיבי בתעשייה.
הערה בקשר לגיבוב סיסמה:
שים לב שמבחינת אבטחה יש לשמור בבסיס הנתונים רק גיבוב + מלח.
המלח זה קשקוש שאתה מייצר בעת בחירת סיסמה, והוא עושה שהסיסמה מורכבת ממה שהמשתמש בחר + הקשקוש שיצרת, מה שעושה את הגיבוב לייחודי אף ביחס לאותה סיסמה.
הגיבוב זה תוצאת פונקציית גיבוב תקנית כמו SHA1 על התרכובת של הסיסמה והמלח.
בעת כניסה אתה לוקח מהמסד את הגיבוב והמלח, ובודק אם פלט הפונקציה על קלט הסיסמה של המשתמש יחד עם המלח מביא את אותו גיבוב ששמור לך.