אבטחה בסיסית עם דרופל למתכנתים

מבוא לאבטחה בכלל ואבטחה בדרופל בפרט. הסבר על סוגי פרצות והגנות.

להלן תמליל מתוך הרצאתי על דרופל ואבטחת מידע שהעברתי בכנס דרופל קאמפ 2014. אני מצרף גם את המצגת, אפילו שאין צורך במצגת על מנת להבין את ההרצאה.

סייבר – התדמית

אבטחה היא המילה הלוהטת בשנה או שנתיים האחרונות. עוד שניה וגם בגן של הבת הקטנה שלי יתחילו ללמוד חוג 'סייבר'. בדרך כלל, כשאנחנו חושבים על אבטחת מידע או 'סייבר' אנחנו מדמיינים חבורה של אולטרא מתכנתים מבריקים שיושבים סביב מלא מסכים בשכבה 8 של הדי פווב – שני ביטים והם מפוצצים לכם את האתר.

סייבר – מציאות

המציאות היא מעט פחות נוצצת. רוב ההאקרים הם סקריפטים אוטומטיים שמנסים לפרוץ לכם את האתר על מנת לשתול בו לינקים לפרסומות. במקרה הפרטי שלנו בישראל, מדובר בילדים אינדונזיים משועממים שמנסים לפרוץ לאתרים ישראלים באמצעות כלים אוטומטיים ולשתול שם תמונות זוועה עם אנגלית מקולקלת.
בסופו של יום, על מנת להתגונן משני האיומים האלו בהצלחה צריך להכיר וליישם מתודולוגיות בסיסיות של אבטחת מידע. על מנת ליישם מתודולוגיות של אבטחת מידע צריך להכיר את הדרכים שבהן כותבי הסקריפטים האוטומטיים משתמשים.
בהרצאה הזו אנחנו הולכים לדבר על דרכים פופולריות לפריצת אתרים בכלל ואתרי דרופל בפרט. אני מסביר על שיטות ההתגוננות הרלוונטיות בנוגע לכל פריצה בין אם מדובר במודולים או בטכניקות קוד לכותבי מודולים.
בסיום ההרצאה אתם תבינו יותר טוב את כל נושא אבטחת המידע ותוכלו לבנות אתרים מאובטחים יותר עבורכם ועבור הלקוחות שלכם. להבין יותר טוב אבטחת מידע לא אומר להפוך להאקר. אני לא האקר ומעולם לא פרצתי לאתר. טוב, לפחות לא פרצתי להרבה אתרים. אבל מספיק להכיר את שיטות הפריצה בלי ליישם אותן בפועל בשביל להגן על האתרים שלכם.

שרת מול אפליקציה

כשאני מדבר על אבטחת מידע, חשוב לי לומר שאני מדבר על אבטחת המידע של הדרופל עצמו בשונה מאבטחת המידע על השרת עצמו. השרת עצמו – כלומר מערכת ההפעלה, השרת עצמו: אפאצ'י או NGINX ואבטחת המידע עליו הם נושאים אחרים שעליהם אני לא ארחיב את היריעה בהרצאה הזו. מרבית הפריצות הסקסיות שהיו בשנה האחרונה מ-Poodle ועד hearbleed היו פרצות ברמת השרת. אם אתם מנהלים את השרת שלכם בעצמכם, אני מניח שאתם מודעים לאיך להקשיח אבטחת שרתים. אם אתם משתמשים באכסון שיתופי, מאוד חשוב להקפיד על אכסון שיתופי מספיק איכותי. שום אפליקציה לא תהיה בטוחה אם השרת שעליה היא יושבת יהיה חדיר. וגם להיפך – גם השרת המוקשח והמוקפד ביותר יהיה חדיר לחלוטין אם האפליקציה חדירה. כאמור בהרצאה הזו אני מדבר על צד האפליקציה.

אז כשאני רוצה לחדור לאפליקציה? איפה אני מתחיל?

XSS

הפריצה האהובה ביותר עלי וזאת שמופיעה המון פעמים היא XSS שזה ראשי תבות של Cross Side Scripting. איך הפריצה הזו עובדת? הפריצה בגדול היא היכולת של התוקף לשתול JS באתר.

נשאלת השאלה למה זה כל כך גרוע? טוב, הוא יוכל לשתול ALERT מרגיזים ולעצבן את המשתמשים, אבל זה לא משהו שיכול להפיל אתר, נכון? התשובה היא שקר. ברגע שתוקף יכול להריץ JavaScript על האתר שלנו, הוא יכול לפרוץ? איך? על ידי שליחת פרטי ה-cookies או ה-session שלנו אל השרת שלו ושימוש בהם על מנת לבצע לוגין כמשתמש רשום או אפילו כאדמין. ככשמנהלי אתרים מתלוננים על כך שנעשים שינויים באתר שלהם בלי שהם יודעים מי עשה את זה והלוגים מראים שמדובר במשתמשים לגיטימיים שנשבעים שהם לא פרסמו עשרות אלפי קישורים ל'קנה עכשיו ויאגרה', סביר להניח שמדובר ב-XSS.
הבדיקה של XSS היא קלה ביותר לביצוע – פשוט להכניס alert פשוט של JS בשדה טקסט כלשהו. או כפרמטר. חטפתם alert? סימן שאפשר להשתיל שם איזה קוד שרוצים.
את ה-XSS מונעים בהכנסת פלט משתמשים ובהדפסה של כל פלט שהוא, לא רק של המשתמשים אלא כל פלט שהוא ועוד מעט אסביר למה.
אז בואו ונדבר על ההכנסה:
אם אתם משתמשים ברכיבי CCK סטנדרטיים של דרופל, בדרך כלל לא צריכה להיות לכם בעיה בכלל. כל עוד אתם דואגים לא לתת את הפילטר שמאפשר למשתמשים להכניס JavaScript לתוך שדות הקלט. כשיש פריצות הן מגיעות משם. בוטים זדוניים פותחים חשבונות, מכניסים קוד JS שגונב את העוגיות של כל מי שרואה את העמוד הזה וכך משיגים sessions של משתמשים ואדמינים. איך מונעים את זה? נותנים את הרשאות כתיבת ה-JS, אם ממש מוכרחים, לחשבונות שצריך איזושהי מידה של אותנטיקציה בשבילם. רק מנהלים למשל, או נושאי תפקידים שלא מתקבלים באופן אוטומטי. באחד המוצרים שפיתחתי, ניתנה ההרשאה רק ל-role מסוים שאושר אוטומטית לפי API חיצוני. כך בוט שיצור חשבון חדש, לא יזכה ל-role שיאפשר לו להכניס JS.

אם אתם מפתחים מודול, עליכם להקפיד ב-form validation hook לוודא שאי אפשר לבצע XSS. בגדול מה שרצוי לעשות זה להשתמש ב-Drupal XSS Filter שזו פונקציה שמעיפה כל תגית שאתם לא מאשרים לה להתקיים. אני פשוט יוצר משתנה גלובלי שבו יש את רשימת התגים שאני מאשר ובכל פעם ש-drupal_xss_filter רצה אני קורא לרשימת התגים הזו.

מאוד חשוב לזכור ש-xss לא מתחבא רק ב-script. אם תכנסו לאתר https://html5sec.org/ תגלו שיש המון פרצות xss שמאפשרות לשתול JS בלא מעט תגיות תמימות למראה. אחת הפרצות למשל משתמשת ב-attribute של onerror בתגית video והפרצה הזו אפקטיבית לאינטרנט אקספלורר ולפיירפוקס. אז אם אתם מאפשרים video למשתמשים שיכולים להרשם out of the blue, תצטרכו לודא שהם לא מסוגלים להשתמש ב-on error. מבט מהיר ברשימה הזו יעורר אצלכם צמרמורת. בכל מקרה, בגלל זה עדיף להגביל כמה שאפשר הכנסת טקסט שהוא לא plain text אצל משתמשים ברמות ההרשאה האוטומטיות.
אני מקוה שאני לא צריך להסביר למה אבטחה ברמת ה-JS היא לא רלוונטית כאשר מדברים על התקפות מהסוג הזה. JS הוא קל לניטרול ולמניפולציה וכל מי שהפעיל אי פעם firebug יודע את זה. פילטור של HTML ברמת ה-JS בצד הלקוח הוא מצוין עבור לקוחות תמימים ומומלץ לעשות אותו על מנת להקל על השימושיות. תוספים כמו WYSIWYG שהכפתורים שלהם מכילים רק את ה-HTML שהלקוח יכול להכניס הם מצוינים עבור שימושיות אך לא עבור אבטחה כי אפשר בקלות לנטרל את ה-WYSIWYG. תוסף שמתריע בפני משתמש שהוא משתמש ב-HTML לא חוקי או מנקה את ה-HTML בשבילו הוא נהדר, אבל כאמור קל לנטרול. אי אפשר לסמוך על אבטחה בצד הפרונט אנד ואנו חושדים לכל מה שמגיע מהלקוח.

אני נוהג לעשות ולידציה בצד הלקוח וכך אני בטוח במאה אחוזים במהלך הולידציה של הנתונים שאם אני מקבל משהו חשוד, אז מדובר במישהו או משהו שמנסה לפרוץ. אם יש לי WYSIWYG שיש בו כמה כפתורים ופתאום אני מקבל בשדה הפלט תגית script, זה מישהו שיודע מה שהוא עושה ואני מיד מפעיל watchdog ורושם את הנתונים הרלוונטיים – יותר מדי הפרות? מייל או השבתה מידית של החשבון – תלוי באתר.

זה היה בנוגע להכנסת נתונים אל מסד הנתונים. צד מעט יותר מוזנח של מניעת ה-XSS הוא בצד הדפסת הנתונים ללקוח. הרבה מתכנתים לא עושים את זה, גם אני לפעמים, אבל זה חשוב מאוד. למה זה חשוב? הרי אם עשינו פילטור או סנטיציה של הנתונים, למה להזיע כשאנו מדפיסים אותם חזרה? מה עשינו רע? התשובה היא ש:
א. אולי אנו או המתכנת השני (בטח שזה הוא!) התרשלנו.
ב. לא תמיד הנתונים שאנו מדפיסים אמינים.

כדי להמחיש את ב'. אני אתן שתי דוגמאות שעל פניו נראות תמימות לחלוטין- בוא ונניח שיש לנו משהו בסגנון הזה:

<body class=”<?php print arg(0); ?>”></body>

לכאורה מדובר במשהו פשוט ולעניין. קוד שהרבה מתכנתים יוצרים באופן פשוט וקל כדי להקל על העיצוב. arg 0 הוא שם הפרמטר הראשון בכתובת שלנו ואנו יכולים להעזר בו כדי להבחין בין סוגי דפים ולעצב אותם באופן שונה ב-CSS. אבל תוקף מיומן יכול להכניס משהו בסגנון הזה:

mydrupal.com/”<script>alert(‘ff’)</script>

בתצורות מסוימות של השרת, זה גם יכול לעבוד. התוקף שולח את 'כתובת הדף' או מפרסם אותה וברגע שמשתמש כלשהו נכנס לכתובת הזו – יש לנו session.

דוגמה יותר טובה היא הסתמכות על המשתנה הגלובלי של ה-server. לכאורה אין דבר יותר בטוח מזה – הרי מדובר ב-server שלנו! אין דבר יותר בטוח ממנו. הבעיה היא שיש שם פרמטרים בלתי בטוחים – כמו למשל

$_SERVER['HTTP_REFERER']

שתוקף פשוט יכול לשנות. משהו בסגנון של דף 404 שאומר:

You came from $_SERVER['HTTP_REFERER'], but you got 404

אבל קל מאוד לזייף את ה-refferrer הזה בכמעט כל אמצעי שהוא – כי למרות שהוא מופיע ב-SERVER, בפועל הוא מגיע מהמשתמש. אם המשתמש יצור הפניה מאתר בשליטה שלו עם הזיוף, כל מי שילחץ על הלינק הזה ויש לו חשבון משתמש באתר שלכם – יהיה חשוף לגניבת session.

יש עוד מיליון דרכים להכניס script במיליון מקומות. במיוחד בדרופל כאשר יש פונקציות כמו arg שלא עושות ולדיציה או סניטציה לנתונים שלהם. בגלל זה כאשר אתם בשכבת הטמפלייט, חשוב מאוד לעשות סניטציה לכל משתנה. סניטציה, בניגוד לולידציה, פירושה הסרה של כל מה שהוא לא ב-whilte label שלנו. אפשר להשתמש ב drupal_xss או, במקרה שאתם יודעים שלא צריך להיות שם HTML בכלל – בפונקצית check_plain שהיא פונקצית דרופל שממירה כל HTML ותוים מיוחדים לישות HTML ומונעת בפועל שימוש במחרוזת הזו ל-XSS.
אם אתם עושים את כל הזמן, בכל פרמטר שאתם מדפיסים ללקוח, אתם ממזערים את סיכוי התקפת ה-XSS.

CSRF

פרצה נוספת שהמון בוטים משתמשים בה בהמון וריאציות היא CSRF או Cross Site Request Forgery. היא מאוד פשוטה וגם בה קל ליפול במיוחד אם אנו מייצרים טפסים משל עצמנו.

קודם כל מה זה? דרך הפריצה הזו רוכבת על משתמש עם session קיים ודרך ה-session שלו גורמת לו לעשות פעולות שונות. על מנת להמחיש, בואו נדמיין שיש לי טופס מחיקת תוכן שמשתמש ב-GET

http://www.mysite.com/?action=delete&nid=NID

בוא ונניח שב-form validation או במקום אחר אני בודק היטב את ה-SESSION וההרשאות של המשתמש. הכל מעולה, נכון? ואז משתמש עם session פעיל מקבל מייל עם תמונה של בר רפאלי ולינק שמזמין אותו ללחוץ על התמונה כדי לקבל תמונה שלה בלבוש חווה.

<a href=”http://www.mysite.com/?action=delete&nid=NID”><img src=”See_bar_naked.png” /></a>

אם ה-session פעיל, המשתמש עכשיו עשה פעולה שתעבור כל ולידציה שלנו ועדיין תהיה פריצה. אם ההנדסה החברתית שלנו מספיק טובה/ המשתמש מספיק להוט אחר הגברת רפאלי, הוא עוד יכניס את שם המשתמש שלו והסיסמה במידה וה-session שלו פג.

כמובן שהלינק יכול להיות הרבה יותר מתוחכם, לשלוח בקשות POST ובאמת לספק תמונה של הגברת רפאלי למשתמש התמים והדביל.

ההתגברות על CSRF נעשית באמצעות פרקטיקה פשוטה שנקראת token והיא מאוד קלה למימוש בסביבת דרופל. בכל יצירה של טופס אנו יוצרים token, שהוא מחרוזת טקסט ארוכה עם המון ג'יבריש. המחרוזת הזו משתנה בכל פעם שהטופס מרונדר מחדש. כאשר אנו שולחים את הטופס, אנו שולחים את אותו token לצד השרת. צד השרת מקבל את ה-token ומוודא שהוא שייך לטופס הזה והוא ג'ונרט עם הטופס. במידה ולא, הוא לא יעביר את הפרטים הלאה. השיטה הזו מופיעה כמובן בדרופל וכמעט בכל מערכת. בדרופל מממשים אותה ככה: קודם כל הדפסת ה-token בטופס נעשית על ידי טוקן.

SQL injection

טכניקה מוכרת נוספת לפריצה לאתרים היא SQL injection.

מדובר בטכניקה חביבה שמרוב שהיא מוכרת קשה לראות היום פריצות בטכניקה הזו, אבל לא מזמן היתה פריצה לליבה של דרופל בהתבסס על הפריצה הזו. SQL Injection היא נושא שלם להרצאה שלמה, אבל אני אתן דוגמה קטנה רק כדי להבין במה מדובר. בוא ונניח שיש לי שאילתה שמוצאת את הפרטים של המשתמשים שלי ומציגה אותם בדף. משהו בסגנון של :

השאילתה רצה בתוך הפונקציה הבאה:

function show_user_profile() {
if(‘user_profile’ == arg(0) {
arg(1) == $account_id;
db_query("SELECT * FROM users WHERE uid = $account_id”)->fetchObject()
//Display issues
}

הפורץ יכול בקלות לנסות ולקרוא את /user_profle/WHATEVER_ID כדי לקבל את הפרטים של כל משתמש. הוא יכול לעשות נזקים רציניים אם הוא (למשל) יקרא ל

user_profle/1'; DROP TABLE users; –'/

אז כל הטבלה תמחק.
זו כמובן דוגמה קטנה של SQL injection אבל היא ממחישה היטב את הרעיון – באופן עקרוני התוקף יודע שכל המידע מתקבל ממסד הנתונים על בסיס המידע שהלקוח מכניס בדרך זו או אחרת. המידע הזה יכול להיות דרך ה-URL, דרך ה-referrer או דרך form מסוים.
מה הפתרון? לפלטר את הקלט מהמשתמש כמובן ולעשות לו סנטיציה. במקרה הזה למשל לוודא לפני כל query שה-uid הוא מספר. דרך נוספת וטובה היא להשתמש בפונקציות הכנסת המידע של דרופל 7 שנעשות עם PDO. זה ימנע כמעט באופן מוחלט את ה-SQL injection.

יש עוד מגוון של סיכונים ברשת, אבל אלו שלושת הסיכונים העיקריים ואלו שלושת הדרכים להמנע מהם אם אתם כותבים את הקוד שלכם.

PITFALLS

הבעיה היא שאחד היתרונות הגדולים של דרופל היא שאנו לא כותבים את רוב הקוד לבד. יש כמה pitfalls להמנע מהם כאשר אנו מסתכלים על מודול. אם יש לכם זמן לעשות code review על מודולים שאתם עובדים איתם, מומלץ להסתכל על הקוד. כיוון שכולנו עצלנים, לפחות מומלץ מאוד להסתכל אם במודול יש:

check_plain
token
xss
->fetch_object

אם המודול מבצע איזושהי אינטראקציה עם views, מומלץ לודא שהוא כולל את בדיקת ההרשאות של ה-view. יצא לי לבדוק כמה מודולים שהגיבו עם view ומשכו ממנו מידע ולא בדקו את בדיקת ההרשאות.

בנוסף לבדיקות קוד, יש כמה דברים שאפשר לעשות בנוגע להתנהלות היומיומית עם דרופל על מנת להגביר את האבטחה.

משתמש ראשי לא admin

משתמש הניהול לא יכול להיות admin. למה? כי אז אני יכול בקלות לעשות brute force ולפצח את הסיסמה. בכל מקרה, גם אם שם המשתמש הניהולי שלכם הוא לא admin, כדאי לודא שאי אפשר לנסות את שם המשתמש והסיסמה יותר מדי פעמים על ידי brute force:
https://www.drupal.org/project/login_security

לא להוריד תבניות ממקומות מפוקפקים

אחד מהדברים החשובים ביותר הוא לא להוריד תבניות ומודולים ממקומות מפוקפקים. ראיתי יותר מדי אתרים שמשתמשים בתבניות מפוקפקות. בדרך כלל התבניות האלו מכילות קוד PHP מוסווה, שנקרא obfuscated, הקוד הזה מכיל כל טוב: ממשלוח כל פרטי האתר לצד שלישי כלשהו ועד השתלת פרסומות לויאגרה במקום הכי פחות נוחים. במידה וכבר הורדתם, מומלץ לחפש קוד כזה – בדרך כלל על ידי חיפוש מחרוזת הטקסט eval שבה משתמשים כדי לפרוס את הקוד הזה ולהריץ אותו. אם הוא מופיע, מומלץ לפתוח אותו ולראות מה הוא מכיל ולעשות ניתוח מדויק כדי להסיר אותו. אם זה נשמע לכם כמו מדע בדיוני, בעולם הוורדפרס יש אתרי תבניות ישראלים שמציעים תבניות שמכילות קוד כזה שבאופן תיאורטי אפשר להשתמש בו על מנת לפרוץ לאתרים.

התקנת מודול security review

על מנת להקל על העבודה שלנו בכל הנוגע לאבטחת אתר, מומלץ להתקין את security_review שמסייע בבדיקת חלק מהדברים שציינתי ועוד – מוודא למשל ששגיאות ה-PHP לא יודפסו וכך לא יתגלה בפני הלקוח/פורץ מידע מביך אם יש בעיה עם האתר/סקריפט או אם הוא הצליח להקריס את האתר.

הסתרת העובדה שאתם משתמשים בדרופל

לפעמים הדרך הטובה ביותר להגנה היא להחביא את העובדה שאתם משתמשים בדרופל – acquia פרסמו הסבר איך לעשות את זה שנמצא כאן: https://docs.acquia.com/articles/hiding-fact-your-site-runs-drupal הסוואת העניין הזה תמנע הפצצה של האתר שלכם בבוטים בכל פעם שמוצאים חור אבטחה בדרופל או במודול פופולרי ובכל מקרה מומלץ להמנע לתת לתוקפים ולסקריפטים מידע שיעזור להם.

עד כאן בנוגע לאבטחה באתרים. למדנו כאן על כמה שיטות פריצה פופולריות וההגנה מפניהן וגם על התנהלות בדרופל כמנהלי אתרים שיכולה לסייע מאוד בכל הנוגע לאבטחה. לא הרחבתי את היריעה כאן על השלב החשוב של האבטחה – להחזיק גיבויים תקינים גם של הקוד וגם של מסד הנתונים ולהחזיק בידע הנדרש על מנת לשחזר את האתר כמה שיותר מהר. אבל על זה, אולי, בהרצאה אחרת.

פוסטים נוספים שכדאי לקרוא

תמונת תצוגה של מנעול על מחשב
פתרונות ומאמרים על פיתוח אינטרנט

הגנה מפני XSS עם Trusted Types

תכונה ב-CSP שמאפשרת מניעה כמעט הרמטית להתקפות XSS שכל מפתח ווב צריך להכיר וכדאי שיכיר.

גלילה לראש העמוד