טעויות אבטחה נפוצות באפליקציות Mobile, וכיצד נוכל להימנע מהן
פיתוח אפליקציית Mobile הינו משימה לא פשוטה: אתם רוצים לספק את המוצר עם חווית המשתמש הטובה ביותר האפשרית, ובזמן הפיתוח הקצר ביותר כדי שאף אחד לא ישיג אתכם עם רעיון המיליון דולר שאתם עובדים עליו. הבעייה בתנאי העבודה האלו היא הנטייה הטבעית לשכוח דבר מאוד חשוב: אבטחת המידע של היישום שלנו. בפוסט זה אנסה לעזור לכם להבין את סכנות אבטחת המידע שאתם צפויים להתקל בהן, וכיצד בנייה נכונה של הארכיטקטורה והקפדה על מספר עקרונות פשוטים תעלה משמעותית את הסיכוי שלכם להוציא אפליקציה מאובטחת.
1. ממה אנחנו חוששים
סכנות אבטחת מידע אורבות בכל מקום, ומפתחים רבים יטענו שזה ממילא לא משנה איך נכתוב את האפליקציה, כי הרי לכל דבר אפשר לפרוץ. זה חצי נכון: חלק מהרכיבים בארכיטקטורה שלנו אינם בידיים שלנו, אנו סומכים על שרת ה Web, על מערכת ההפעלה, על מערכת ההפעלה של הטלפון ועוד אינספור ספריות קוד בהן אנו משתמשים בכתיבת כל יישום. חולשות ברכיבים אלו יכולות להוביל לפריצה לשרתים שלנו או להוביל לאובדן נתונים פרטיים של המשתמשים שלנו.
האתגר שלנו יהיה להבטיח שלפחות הקוד אותו אנו כן כותבים ימומש באופן מאובטח.
אוסף הרכיבים המועדים לפירצה במערכת טיפוסית הכוללת שרת ואפליקציית Mobile נראה בערך כך:
צד הלקוח מורכב מקוד האפליקציה ומערכת ההפעלה של הטלפון, ובצד השרת יש לנו את הקוד שאנו כותבים בשפת צד השרת שנבחר, ואת הפלטפורמה עצמה שהיא מערכת ההפעלה, שרת ה Web, ורכיבים אחרים שרצים על השרת.
בנוסף לרכיבים הטכניים, מערכות רבות מכילות גם היבט אנושי — נציגי שירות לקוחות או תמיכה, אשר דרכם פורץ עלול להשיג גישה לפרטים חסויים של המערכת.
לגבי הפלטפורמה אין לנו הרבה מה לעשות מלבד להקפיד לשדרג את רכיבי התוכנה בהם אנו נעזרים בכל הזדמנות. פרצות קריטיות חדשות מתגלות חדשות לבקרים, וחבל לאבד מידע יקר רק בגלל שהתעצלתם לשדרג את בסיס הנתונים או מערכת ההפעלה.
אמשיך בתיאור בעיות האבטחה הנפוצות ברכיבים השונים של המערכת.
2. בעיות אבטחה מצד הגורם האנושי
ביולי 2013 האקרים (ככל הנראה סורים) פרצו לאפליקציית Viber והשחיתו את עמוד התמיכה באתר החברה. הנה ההסבר לפריצה כפי שהתקבל מחברת Viber:
Today the Viber Support site was defaced after a Viber employee unfortunately fell victim to an email phishing attack. The phishing attack allowed access to two minor systems: a customer support panel and a support administration system. Information from one of these systems was posted on the defaced page.
זה לא נעים כשהאקרים מרמים את אנשי התמיכה שלכם וכך מקבלים גישה למשאבים, אבל הדבר החשוב לשים לב כאן הוא שהנזק לא היה גדול, ותוקן במהרה. העמוד שהושחת הוחזר לקדמותו, הסיסמאות שונו וננקטו אמצעי זהירות לפעם הבאה. מה שעמד לטובתם של אנשי Viber היה ככל הנראה המידור בין המערכות. הפורצים קיבלו גישה למערכת התמיכה, אך לא הצליחו לקבל נתונים אישיים של משתמשים.
עבור איביי הסיפור נגמר אחרת לגמרי. במאי 2014 חברת איביי הודיעה לכל המשתמשים שלה להחליף בדחיפות ססמאות, לאחר שהאקרים פרצו למערכות שלהם וגנבו פרטי התחברות של 230 מיליון משתמשי איביי. המתקפה היתה שוב מתקפת פישינג על עובדי החברה. ארכיטקטורת שרתים שונה ופחות דגש על מידור הביאו לסיום אחר לגמרי של הסיפור.
בשורה התחתונה: כשאתם מתכננים את שרתי ה Production שלכם, שימו לב היטב למי יש גישה ומה מידת הגישה של כל משתמש. נסו לבנות את המערכת כך שלא יהיה משתמש אחד שיוכל לגשת לכל המידע השמור על השרת או בבסיס הנתונים.
3. בעיות אבטחה בצד השרת
בעת כתיבת קוד צד השרת עלינו לזכור כי אפליקציית ה Mobile שאנו כותבים לא תהיה הלקוח היחיד שלנו. גם אם אנו לא כותבים API מתועד באופן מפורש, כל אחד יכול לקחת את אפליקציית ה Mobile, לראות את המידע שהיא שולחת ומקבלת מהשרת ולבנות על בסיס המידע הזה סקריפטים שישלפו מידע רגיש מהשרת, או יגרמו לשרת להתנהג באופן לא צפוי. נתחיל בכמה דוגמאות ואז נסכם עם המלצה.
כותבי אפליקציית Tinder חיפשו להקל מהעומס על השרת שלהם, והחליטו להעביר חלק מפעולות האפליקציה לצד הלקוח. בפרט, כשביקשתם מהשרת של טינדר רשימה של מועמדים פוטנציאליים להיכרות באזור שלכם, השרת שלח לאפליקציה גם את המרחק המדויק של כל מועמד, ואפליקציית ה Mobile מיינה אותם לפי מרחק.
המידע שהתקבל משרת Tinder היה מערך של אובייקטי מידע, כל אחד מהם נראה בערך כך:
{
"photos":[ ... ],
"id":"52617e698525596018001418",
"common_friends":[],
"common_likes":[ ],
"common_like_count":0,
"common_friend_count":0,
"distance_mi":4.760408451724539
}
האפליקציה עצמה לא מראה את המרחק המדויק של כל מועמד אלא מעגלת את המספר. המידע העודף משמש את האפליקציה לצורך מיון.
חדי העין שביניכם כבר הבינו שהמידע העודף שהשרת שלח לאפליקציה יכול לשמש תוקפים זדוניים בקלות: אם תוקף זדוני ירצה כעת לגלות מיקום מדויק של גולש בטינדר, כל שעליו לעשות הוא להתחזות למישהו שנמצא באזור 3 פעמים, כל פעם בנקודה אחרת, ולהצליב את התוצאות. זה נראה כך:
למרות המשיכה הגדולה בכתיבת קוד שרת המנותק מאופן ההצגה, והרצון להעביר את הטיפול באופן ההצגה לקוד הלקוח, עלינו לזכור שכל מידע שאנו שולחים ללקוח עלול לשמש נגדנו.
אם גם אתם רוצים לעקוב אחר מידע שעובר בין אפליקציות שרצות לכם על הטלפון לשרת שלהן, כל שעליכם לעשות הוא להתקין תוכנה חינמית שנקראת Fiddler ולקנפג אותה כך ש״תתפוס״ את כל המידע שעובר ותציג אותו בנוחיות על מסך המחשב שלכם. כאן תמצאו קישור למדריך כיצד להתקין ולהגדיר את Fiddler לצורך זה:
http://docs.telerik.com/fiddler/configure-fiddler/tasks/ConfigureForAndroid
תקלה מעניינת נוספת בהקשר זה התגלתה ממש החודש בפייבוק, כאשר האקר בשם Laxman Muthiyah החליט לבדוק את המידע שאפליקציית פייסבוק מעבירה לשרת וגילה דבר מעניין. לקסמן החל את דרכו בתיעוד של ה Graph API, שם הוא גילה שאין לאפליקציה חיצונית שהוא כותב אפשרות למחוק אלבומי תמונות כלל, גם אלבומים השייכים לכם.
למרות מגבלה זו, לקסמן שם לב כי אפליקציית האנדרואיד של פייסבוק דווקא כן מאפשרת מחיקת אלבומים, מה שגרם לו להתחיל לתהות האם פייסבוק משתמשת ב API נפרד עבור האפליקציות ולמה לקוח אחד רשאי לבצע את פעולת המחיקה בעוד שלקוח אחר לא רשאי.
לקסמן המשיך לחקור את הנושא וגילה כי פייסבוק משתמשת באותו ה API גם לאפליקציית האנדרואיד שלה. בחיבור הראשוני של משתמש דרך אפליקציית אנדרואיד המשתמש יקבל יותר הרשאות מאשר אם היה מתחבר דרך אפליקציה אחרת (באצעות Access Token שונה). לקסמן לקח את ה Access Token של אפליקציית האנדרואיד, וגילה שבעזרתו הוא יכול בקלות למחוק את אלבומי התמונות שלו, ובנוסף גם כל אלבום תמונות של כל משתמש פייסבוק אחר.
בעת כתיבת קוד צד-השרת, פייסבוק התעלמו מהאפשרות שאפליקציית אנדרואיד תנסה לבצע פעולה כמו מחיקת אלבום של משתמש אחר, ולכן לא בדקו הרשאות על המחיקה בצד השרת, והסתפקו בשוגג בבדיקה בצד הלקוח. מיותר לציין שהבאג תוקן תוך מספר שעות ממועד הדיווח, ולקסמן זכה בגמול המוצא הישר מפייסבוק.
בשורה התחתונה: אפליקציית Mobile איננה שונה מכל תוכנת שרת-לקוח אחרת. העובדה שהיא רצה על הטלפון לא מגנה על התקשורת כלל. בעת כתיבת השרת עליכם תמיד להניח שהלקוח שמדבר אתכם איננו האפליקציה שכתבתם אלא תוקף זדוני, שמכיר את קוד השרת ואת קוד האפליקציה ומוכן לעשות הכל כדי לשלוף מידע סודי ולהפיל את השרת.
בנוסף, מומלץ לתת דרך קלה לאנשים לדווח לכם על תקלות אבטחה במערכת. כמובן שתוכנית Bounty יכולה לעודד האקרים חברותיים ולסייע לכם למצוא תקלות, אבל גם טופס בו משתמש יכול לדווח על תקלות אבטחה או כתובת אימייל אליה אפשר לשלוח פרטים טכניים של תקלה זה הרבה פעמים מספיק טוב.
4. בעיות אבטחה בצד הלקוח
תפקידה של האפליקציה מבחינת אבטחת המידע הוא להגן על המידע הפרטי של המשתמש מגורמים עוינים. גורמים אלו עלולים להשתלט על הרשת, על מכשיר הטלפון או על כל אלמנט סביבתי אחר. בעת כתיבת האפליקציה עלינו לזכור שכל מידע שאנו שומרים וכל תקשורת שאנו מקיימים עלולים לסכן מידע רגיש.
את הנקודה הזו בדיוק שכחו בחברת אפל, כאשר הוציאו את iOS4 והחליטו לשמור את מיקום הגולש בכל רגע נתון בקובץ על הטלפון (כחלק מפיצ׳ר חדש של מערכת ההפעלה). אף אחד לא זוכר מה היה הפיצ׳ר, אבל את פרשיית המעקב האינטרנט יזכור להם לשנים רבות.
אני יכול לדמיין את הישיבה בה החליטו על שמירת מידע זה בקובץ לא מוצפן, וכשמישהו שאל האם לא עדיף לשמור את הקובץ במקום פרטי בטח הסבירו לו ש״אנחנו סך הכל שומרים את המיקום של בעל הטלפון, הרי מי שהטלפון בבעלותו יודע איפה הוא היה לא?״. אז זהו… שלא. כל אחד שלוקח עכשיו טלפון יודע בדיוק איפה בעל הטלפון היה בכל רגע, וזה כבר מסכן את המשתמשים שלנו.
סוג נוסף של בעיות בצד הלקוח נובע מאחסון לא מאובטח של מידע סודי כחלק מקוד האפליקציה. קחו לדוגמא אפליקציה השומרת מידע על שרתי S3. אם נשמור כחלק מקוד האפליקציה את מפתח התקשורת (ה AWS_SECRET) — כל משתמש יוכל לשלוף אותו מקוד האפליקציה.
כל פריט מידע או מפתח סודי שאתם מאחסנים בקוד האפליקציה ככל הנראה ייפול לידיים עוינות. מסיבה זו עלינו לכתוב את הקוד כך שכל המידע הסודי נשמר אצלנו בשרת. לדוגמא, אפליקציה שצריכה לקרוא נתונים משרת S3 של אמאזון לא תדבר ישירות עם אמאזון אלא תעזר בשרת שלנו שידבר עם אמאזון, וכך נבקר על הגישה ולא נחשוף את מפתח התקשורת.
אפשרות נוספת היא להחזיק מפתח מוחלש עבור אפליקציות. כך למשל עובד השרת של Parse.com. כל חיבור ל Parse מצריך מזהה אפליקציה, שם משתמש וסיסמא, והמפתח ששמור על הטלפון מאפשר גישה רק בצירוף שם משתמש וסיסמא תקינים.
(פייסבוק משתמשים בדיוק באותה השיטה).
למי שמעוניין לשלוף את קוד המקור של אפליקציית Mobile, אספר על האתר APK Downloader בכתובת:
http://apps.evozi.com/apk-downloader/
באתר זה אתם מקלידים כתובת של אפליקציה בחנות Google Play ומקבלים את ה APK שלה.
אחרי שיש לנו את ה APK אפשר להעזר בכלי APK Tool כדי לפתוח אותו ולהנדס אחורנית את תוכנו:
https://code.google.com/p/android-apktool/
ולאמיצים מבין הקוראים יש גם מדריך כיצד לקחת כל אפליקציית אנדרואיד (גם כזו שלא אתם כתבתם) ולהריץ אותה אצלכם על המחשב במצב Debug כדי ללמוד כיצד היא עובדת ולהוציא ממנה מידע:
http://blog.dornea.nu/2014/08/21/howto-debug-android-apks-with-eclipse-and-ddms/
בשורה התחתונה: מומלץ להתיחס לאפליקציית Mobile המותקנת על מכשיר טלפון של משתמש כמערכת חיצונית, שלמשתמש יש את קוד המקור המלא שלה. כתבו את הקוד כך שגם אם תשחררו את האפליקציה בקוד פתוח, המערכת עדיין תשאר מאובטחת.
5. בעיות אבטחה בשכבת התקשורת
שכבת התקשורת היא אולי הקלה ביותר להבנה ולהגנה. כל שעלינו לעשות הוא לוודא שהתקשורת בין הלקוח לשרת עונה על 3 תנאים:
- וידאנו שאנו אכן מדברים עם השרת האמיתי שלנו.
- כל המידע שעובר בין השרת ללקוח עובר באופן מוצפן.
- וידאנו שלמות (Integrity) של כל המידע שעובר בין השרת ללקוח.
פרוטוקול התקשורת HTTPS מקיים את שלושת הדרישות וגם קל מאוד להשתמש בו לצורך תקשורת באפליקציה. התקינו תעודות TLS בצד השרת והתחברו ב HTTPS בין השרת ללקוח. אם אתם צריכים תקשורת דו-כיוונית יש תוספת לפרוטוקול שנקראת Web Sockets, וגם עבורה יש פרוטוקול מאובטח שנקרא Web Sockets Secure (או wss). בקישור הבא תמצאו מדריך כיצד להתקין ולקנפג תקשורת מסוג זה:
http://blog.arungupta.me/securing-websocket-wss-https-tls-techtip50/
6. סיכום - טיפים לפיתוח מאובטח
פיתוח אפליקציית Mobile אינו שונה משמעותית מפיתוח כל מערכת שרת-לקוח אחרת. לפעמים זמן הפיתוח הקצר וקלות השימוש בכלים וספריות שאולי אנו לא תמיד מבינים עד הסוף מביאים לתקלות אבטחה מביכות ומסוכנות. בפעם הבאה שאתם מגיעים לכתוב אפליקציה, שימו לב להשתמש באותם כללי זהירות שהייתם נוקטים גם מחוץ לעולם ה Mobile. פיתוח כזה דורש כמובן להבין טוב מה כל פונקציה וספריה עושה, וכיצד המערכת עובדת מבחינת גישה לשירותי צד-שלישי, אבל ממילא הבנה זו תעזור לכם לכתוב יישומים טובים יותר.