עשר חולשות אבטחה ביישומי ווב OWASP Top 10 עם דוגמאות קוד ב Node.JS
בשבועיים האחרונים העברתי שני וובינרים על Owasp Top 10, שזו רשימת עשר חולשות האבטחה הנפוצות ביותר ביישומי ווב. בוובינרים עברנו אחת-אחת על החולשות וראינו איך כל חולשה עשויה להתבטא ביישומי ווב בשפת Node.JS וכמובן איך למנוע אותה. בשביל שיהיה מסודר הנה תקציר של כל העשר עם דוגמאות קוד וקישורים לקריאת המשך.
1. הזרקת מידע זדוני
חולשה מספר אחד מלווה אותנו מאז שאני זוכר את האינטרנט והיא נקראת הזרקת מידע זדוני או באנגלית Injection. בכל פעם שתוכנית מקבלת קלט מבחוץ ומשתמשת בו, עליה לוודא שהקלט לא כולל תווים שעלולים לגרום להשפעה לא רצויה.
הדוגמא הקלאסית היא SQL Injection שם קלט ממשתמש הופך לשאילתת SQL, ותווים מסוימים עשויים לאפשר לתוקף לשנות את השאילתה. ב Express עשויה להיות לנו בעיה עם Query String Parameters שלפעמים מומרים ממחרוזת לאוביקט. שימו לב לקוד הבא שמשתמשת ב Mongoose:
const user = await User.findOne({
email: req.query.user.email,
});
כל עוד ערך המשתנה req.query.user.email הוא אכן מחרוזת אין לנו בעיה, אבל אם משתמש ימצא דרך להעביר לשם אוביקט (וזה לא כזה מסובך למצוא), השאילתה שתישלח עלולה להיות אחרת לגמרי ממה שהתכוונתם.
קריאה נוספת על החולשה ומתקפות אפשריות: https://www.owasp.org/index.php/Top10-2017A1-Injection
2. זיהוי משתמש שבור
מסכי לוגין שאנחנו כותבים עשויים להישבר בקלות ובמגוון דרכים: אם תוקף יכול לנסות כל שם משתמש וסיסמא אז בסוף אולי הם ימצאו את הסיסמא הנכונה, אם משתמשים יכולים לבחור לעצמם סיסמאות חלשות אז בסוף מישהו יבחר את הסיסמא password.
אבל הבעיה יכולה להופיע גם בתרחישים הרבה יותר עדינים. שימו לב לקוד הבא שעשוי לשמש חברת תעופה כדי לאפשר חיבור מהיר באמצעות מזהה כרטיס טיסה:
route.post('signin_with_barcode', async function(req, res, next) {
const code = req.query.barcode;
const user = await User.findOne({ barcode: String(code) });
req.login(user, function(err){
if(err) return next(err);
res.redirect('/home');
});
}
הקוד מסתמך על זה שה URL שמשתמש גולש אליו יישאר סודי וכך גם קוד הגישה. בפועל ראינו שמשתמשים מפרסמים תמונות של כרטיסי הטיסה שלהם בפייסבוק, ומהתמונה אפשר לקרוא את הברקוד שעל הכרטיס וכך לגלות את קוד הגישה.
קריאה נוספת על החולשה ומתקפות אפשריות:
https://www.owasp.org/index.php/Top10-2017A2-Broken_Authentication
3. חשיפת מידע רגיש
עם המעבר ליישומי ווב שמשתמשים יותר ויותר בשירותי צד שלישי, אנחנו צריכים לשמור את פרטי הגישה לאותם יישומי צד שלישי בהם אנחנו נעזרים. לא פעם אנחנו שומרים מידע רגיש בקוד התוכנית עצמו. שמירה כזאת מסוכנת שכן עכשיו כל מי שיש לו גישה לקוד גם חשוף לאותם אסימוני גישה, ומספיק לגנוב את קוד המקור כדי להשתלט גם על המידע ששמור באתרי צד שלישי.
מקום נוסף בו חולשה זו מתגלה הוא ב HTTP Headers שנשלחים מהשרת וכוללים את התוכנות שמותקנות על השרת ומספרי הגירסאות שלהן.
קריאה נוספת על החולשה ומתקפות אפשריות:
https://www.owasp.org/index.php/Top10-2017A3-SensitiveDataExposure
4. ישויות חיצוניות ב XML
עבודה עם קבצי XML עדיין נפוצה במערכות ארגוניות והרבה פעמים מנגנון קריאת ה XML לא מקונפג כמו שצריך וכך עשוי להיות פגיע למתקפה של הזרקת קוד זדוני בתוך קובץ ה XML. קחו לדוגמא מערכת שמקבלת XML, קוראת ממנו מידע ולפי המידע הזה יוצרת איזשהו XML להחזיר ללקוח. במקרה כזה אם ה XML Parser לא מקונפג נכון לקוח יוכל לשלוח קובץ XML זדוני, בו יישתלו פקודות מסוג External Entity שיגרמו ל XML Parser להחזיר מידע שלא היה אמור להחזיר או לבצע פעולות שלא היה אמור לבצע.
נתבונן בקובץ XML לדוגמא:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>
אם שרת פגיע ינסה לפענח קובץ זה ולשלוח ללקוח את התוצאה, מה שיקרה זה שהשרת יקרא את תוכן הקובץ /etc/passwd
ויחזיר את תוכן הקובץ בתוך האלמנט foo.
בעולם של Node.JS לא מצאתי XML Parser שמכוון כברירת מחדל לפענח External Entities, אבל כדאי להיות ערניים ולהסתכל בתיעוד אם צריך הגדרה מיוחדת עבור ה Parser שלכם (הכי בטוח זה לנסות לשלוח למערכת שלכם את קובץ ה XML שכאן ולראות איזה XML היא מחזירה).
קריאה נוספת על החולשה ומתקפות אפשריות:
https://www.owasp.org/index.php/Top10-2017A4-XMLExternalEntities_(XXE)
5. בעיה בניהול הרשאות וגישה
ניהול הגישה למערכת צריך להיות מושפע אך ורק מזהות המשתמש שמנסה לבצע פעולה מסוימת, ושגיאה בניהול גישה אומרת שמשתמשים יוכלו לבצע פעולות שאסור היה להם לבצע בדרכים עקיפות, למשל דרך שינוי פרמטר ב URL.
נתבונן בקוד הבא:
router.get('/:user_id', async function(req, res, next) {
try {
const id = new ObjectID(req.params.user_id);
const user = await User.findOne(id);
res.render('users/show', { user });
} catch (err) {
next(err);
}
});
הקוד לוקח מזהה user_id
כפרמטר מהמשתמש ובאמצעותו טוען את פרטי המשתמש שצריך להציג. אם הקוד אמור לאפשר לכל משתמש לראות פרטים של כל משתמש אחר הכל טוב, אבל אם מישהו חשב שהקוד יאפשר רק למי ש"יודע" מה מזהה המשתמש לגשת לפרטים של אותו משתמש אז יש פה טעות. כל אחד יכול לשנות ב URL את שדה מזהה המשתמש ולגשת לפרטים של משתמשים אחרים.
קריאה נוספת על החולשה ומתקפות אפשריות:
https://www.owasp.org/index.php/Top10-2017A5-BrokenAccessControl
6. הגדרות אבטחה שגויות
מערכות רבות נכתבות על ידי אנשים מוכשרים אבל בעליה ל Production משהו נשבר: מישהו שכח להגדיר סיסמא על בסיס הנתונים, מישהו שכח את ה FTP פתוח עם סיסמא דיפולטית וכן הלאה.
מקום נוסף בו חולשה זו יכולה להתבטא יהיה כשהגדרות האבטחה של היישומים לא מתאימים לסביבת פרודקשן (למשל שרת Redis שמוגדר להקשיב לרשת החיצונית), או תוכנה שרצה במצב פיתוח ולכן כל שגיאה תציג יותר מדי מידע למשתמשים.
נסו לתת את אותה תשומת לב לתהליך ה Deployment שלכם כמו שאתם משקיעים בתהליך הפיתוח.
קריאה נוספת על החולשה ומתקפות אפשריות:
https://www.owasp.org/index.php/Top10-2017A6-Security_Misconfiguration
7. סקריפטים בין אתרים (XSS)
כאשר קלט ממשתמש מסוים מופיע ללא ניקוי על דף HTML שנשלח למשתמש אחר, המשתמש הראשון עשוי לשלוח בתור הקלט מידע שיהפוך לקוד JavaScript. במקרה כזה התוקף יכול לגרום לדפדפן של "הקורבן" לבצע כל פעולה בתוך האתר ולפעמים גם באתרים אחרים שהקורבן נשאר מחובר בהם.
בדרך כלל מנוע בניית ה HTML ינקה כל זכר לתווי HTML או קוד JavaScript לפני בניית ה HTML, אבל לפעמים מתכנתים מבטלים את הפיצ'ר הזה כדי כן לאפשר עריכת HTML על ידי משתמשים (למשל ביישום של אימייל שם משתמשים עורכים את המייל בעורך ויזואלי). אז מתחילות הבעיות וצריך להיות מאוד זהירים לגבי תהליך הניקוי שאנחנו מפעילים על הקלט שעובר ממשתמשים למשתמשים אחרים.
קריאה נוספת על החולשה ומתקפות אפשריות: https://www.owasp.org/index.php/Top10-2017A7-Cross-SiteScripting(XSS)
8. פענוח מידע בצורה לא מאובטחת - Insecure Deserialization
מודולים מסוימים ב Node מאפשרים להפוך אוביקטים למחרוזות וההיפך. במקרה כזה אם אתם הופכים מחרוזת שהגיעה ממשתמש לאוביקט אצלכם במערכת עליכם לוודא שהמחרוזת לא כוללת מידע זדוני. שימו לב לקוד הבא:
var str = Buffer.from(req.cookies.profile, 'base64').toString();
var obj = serialize.unserialize(str);
if (obj.username) {
return res.send("Hello " + escape(obj.username));
}
הקוד משתמש במודול שנקרא serialize כדי להפוך מחרוזת שהגיעה מעוגיה לאוביקט מידע איתו עובדים ביישום. משתמש זדוני יוכל לשנות את העוגיה כדי לשתול קוד שירוץ בתוך השרת בזמן שהשרת מנסה לעשות unserialize.
קריאה נוספת על החולשה ומתקפות אפשריות:
https://www.owasp.org/index.php/Top10-2017A8-Insecure_Deserialization
9. שימוש ברכיבים עם חולשות אבטחה מוכרות
באקו סיסטם של נוד מתכנתים רגילים להפעיל npm install בלי לחשוב פעמיים, ותוקפים כבר יודעים לנצל את זה. תוקפים רבים יעלו חבילות זדוניות ל npm רק כדי שתתקינו אותן בטעות (והתוצאה נעה בין גניבת ביטקוינים מהמחשב שלכם ועד הוספת דלת סתרים בשרת).
בנוסף בגלל שאנחנו לא אוהבים לשדרג מספיק שתוקף מזהה שהשתמשתם בחבילה מסוימת בגירסא שיש בה בעיה ידועה ואותו תוקף יוכל לנצל את הבעיה הידועה בחבילה כדי לתקוף את המערכת שלכם.
בעבודה עם נוד חשוב מאוד לייצר תהליך פיתוח בו אנחנו יודעים איזה מודולים נכנסים לנו לקוד, ויש לנו מנגנון ברור של שדרוג מודולים כשבעיות אבטחה מתגלות בהם.
קריאה נוספת על החולשה ומתקפות אפשריות:
https://www.owasp.org/index.php/Top10-2017A9-UsingComponentswithKnownVulnerabilities
10. היעדר מנגנוני תיעוד וניטור
פרצו לכם לשרת. עכשיו מה? מסתבר שיותר מדי מתכנתים משקיעים את הזמן שלהם בבניית חומות חיצוניות ומתעלמים מפיתוח מנגנונים שיאפשרו לנו לזהות פירצות ולהתאושש מהן. ההבדל בין קוד זדוני שנשתל על השרת ורץ במשך חודשים ארוכים לבין קוד זדוני שאיך שמתחיל לעבוד גורם להפעלה של פעמוני אזעקה ונעילת החשבון הוא עצום. ההבדל בין מערכת שיש לה לוגים מסודרים איתם אפשר להבין מה היה לבין מערכת שפתאום מתחילה להתנהג מוזר ואתה אפילו לא יודע אם היתה פריצה הוא עצום.
שמרו לוגים, שמרו אותם על מכונה נפרדת, וודאו שמרגע שלוג נכתב אי אפשר לשנות אותו, הוסיפו מנגנוני ניטור כך שתזהו כשדברים מוזרים קורים על השרת שלכם או כשמידע מתחיל לזלוג החוצה. ואחרי זה תוכלו לקרוא עוד על החולשה ומתקפות אפשריות בקישור כאן:
https://www.owasp.org/index.php/Top10-2017A10-Insufficient_Logging%26Monitoring
ההקלטות של שני הוובינרים שעברו זמינות בדף "הקלטות מוובינרים" כאן באתר, ואם אתם מנויים מוזמנים לקפוץ ולצפות בהן כשיש לכם זמן. בוובינרים הצגתי לכל אחת מהחולשות ספציפית איך נראה הקוד הפגיע ואיך לנצל את הקוד כדי לחדור למערכת, וכמובן מה לעשות כדי להתגונן ולבנות תהליך פיתוח בו לא נכתוב קוד פגיע מלכתחילה.