הבלוג של ארתיום
בלוג על לינוקס, תוכנה חופשית, מוזיקה, סלסה, ומה לא!
כיצד בונים מערכת פרוצה מרכיבים בטוחים קריפטוגרפית
אתמול שחררתי גרסאות CppCMS חדשות בשני הענפים - היציב וענף הבטא שסגרתי בהן באג שקשור לשימוש לא נכון ברכיבים קריפטוגרפיים.
תחילת הסיפור
הסמסטר אני לוקח קורס יסודות קריפטוגרפיה של פרופ' רן קנטי. במהלך הקורס דננו בנושא הצפנה והדרישות של בטיחות.
נגיד, יש לנו אלגוריתם שיודע להצפין בצורה בטוחה: היריב לא יוכל להשיג שום מידע על התוכן של הודעות בהסתכלות על טקסט מוצפן; ואז שואלים שאלות כמו האם זה מספיק, באיזה תנאים וכו'.
עכשיו, נחזור לבעיה שאני מנסה לפתור ב־CppCMS בעזרת הצפנה.
אני רוצה לשמור מידע (session) בצד הלקוח בעוגייה ואני רוצה להבטיח שני דברים:
- הלקוח לא ידע מה אני שומר אצלו.
הלקוח לא יוכל לשנות את המידע ששמרתי;
הגדרת יותר מדויקת: הוא לא יוכל ליצור session (עוגייה) עם מידע שאני לא יצרתי.
הפתרון:
ניקח תוכן שאני רוצה לשמור אותו, נחשב לו checksum בעזרת פונקציה hash ונצפין אותו יחד עם ה־hash. סביר להניח שאם אין יכולת להפוך את הטקסט לטקסט מוצפן ובחזרה אז לא ניתן גם ליצור משהו שהתוכן וה-hash שלו יהיו תואמים.
האם יש אנשים שחשבו כך והשתמשו בזה לפניי? בהחלט כן - פרוטוקול WEP עושה בדיוק את הדבר הזה! אז, כפי שאתם כבר בוודאי יכולים לנחש, מימשתי פתרון דומה ב־CppCMS כדי להבטיח שהלקוח לא ייצור session לא חוקי, רק שהשתמשתי בהצפנת CBC-AES וב־hash קריפטוגרפי ולא ב־CRC32 (כמו שזה היה ב־WEP).
למען הסר ספק, לא השתמשתי בשיטה הזו בגלל שראיתי שימוש בה ב־wep - אני יודע כי wep פרוץ
אז ההרצאה דנה בנושא הצפנה ובטיחות. במהלכה הוצג שהפתרון הזה לא נכון וכלל לא מבטיח בטיחות במקרה כללי! כיוון שלא הצלחתי במהלך ההרצאה להבין כיצד במקרה פרטי שלי אפשר לתקוף את המנגנון הזה, התחלתי לחפש ומצאתי מאמר מאוד מעניין שעוסק ניתוח בעיית ההצפנה ואימות הזהות ביחד ובודק פתרונות שונים.
מי שמעוניין יכול לקרוא את המאמר, אבל בגדול הוא מציג התקפה אמתית (יחסית פשוטה) כנגד השיטה כזו שעובדת עם הצפנה מבוססת CBC ו־hash שמוצמד לסוף התוכן. המאמר קובע כי כל שיטה שמסתמכת על hash פומבי לבדיקת אמתות לא תעבוד. המאמר ממליץ על אימות התוכן המוצפן בעזרת MAC שעובד עם מפתח נוסף.
מה שחשוב שניתן להוכיח בקלות שאם ה־MAC שלנו בטוח וההצפנה בטוחה אז השיטה הזו תהיה בטוחה גם כן.
המעשה
אחרי הבנתי שיש לי באג קריטי במערכת ניהול ה־session בשני הענפים של CppCMS התחלתי לעבוד על התיקון (שהוא בסה"כ תיקון פשוט) ושחררתי גרסה החדש עם התיקון הנדרש.
בדיעבד אני מאוד שמח שלקחת את הקורס הזה, למרות שהוא מסוג הקורסים המאוד תיאורתיים שבד"כ אני לא אוהב ועוסק בנושאים שיחסית רחוקים הקריפטוגרפיה מעשית.
מסתבר שגם כאן, כמו בבכל דבר, אין תחליף לבסיס תאורתי מוצק.
מסקנות
שימוש באלגוריתמים בטוחים לא מבטיח שום בטיחות אם משתמשים בהם בצורה לא נכונה. לכן, בכל פעם שאתה עוסק במשהו קשור לקריפטוגרפיה, אם יש לך אפשרות תן למומחה להסתכל על מה שעשית.
האם אפשר היה לעשות אחרת?
אני חשבתי על זה - אולי אני בכוח מנסה להמציא גלגל קריפטוגרפי המחדש?
אבל ככל שאני חושב יותר, אני מבין שכנראה בהינתן הידע והניסיון שיש לי, לא יכולתי לעשות משהו יותר טוב.
- לא קיים פתרון סגור (קרי ספריה) לבעיה שאני צריך, בד"כ ההצפנה ואימות הן חלק מפרוטוקולים קיימים כמו TLS או SSH והם ממומשים ספציפית עבורם בצורה של תקשורת כך שהמשתמש מקבל API דמוי socket וכל מה שיש למטה מוסתר.
- רוב הספריות נותנות מימוש לש פרוטוקולים קיימים או אבני בניין כמו AES או MAC שאתה אחראי לחבר אותם ביחד בצורה נכונה, כך למשל, אם אתה לא מאתחל נכון את iv באלגוריתם CBC אתה תיצור חור אבטחה בקלות.
- עשיתי כמיטב יכולתי והשתמשתי ברכיבים מוכנים, לא כתבתי מימושים של AES או של SHA1 מחדש, נעזרתי בקוד קיים בדוק ומתוחזק היטב.
הבעיה שהרכבתי את האלגוריתמים קריפטוגרפיים בצורה לא נכונה; ולמען האמת, אני לא הראשון ולא האחרון שעשה דבר כזה - היו גדולים לפני שעשו טעויות כאלה וגם יהיו אחרי.
בהסתכלות לאחור - נראה עשיתי באמת מה שיכולתי. אם לא הייתי מפתח קוד פתוח פרטי אלא מנהל פרויקט בחברה שמפתחת פרויקט כזה אז, הייתי מזמין מומחה כדי לעשות בדיקה לקוד ולהחלטות שעשינו.
רישיון CppDB השתנה ל־BSL/MIT
החלטתי לשנות את רישיון CppDB - ספריית קישוריות ל־SQL לרישיון יותר מתירני רישיון כפול: רישיון Boost או רישיון MIT לבחירתכם.
בגדול, אני הייתי שמח להישאר עם רישיון יחיד - רישיון Boost, אבל ספריית MySQL לא מכילה חריגה עבורו, אז הוספתי רישיון MIT כחלופה. כך שאם אתם משתמשים ב־CppDB וב־MySQL אתם צריכים לנהוג לפי דרישות רישיון MIT.
לשינוי הרישיון היו מספר סיבות:
- אני רוצה לנסות להכניס את הספריה בשלב מסויים ל־Boost, כך ששינוי הרישיון היה מתוכנן בכל מקרה.
- אני מקווה שזה ירחיב את כמות המשתמשים והתורמים לפרויקט ויתן פרסום ודחיפה נוספים ל־CppCMS.
כדי למנוע אי הבנות: CppCMS עדיין משוחרר תחת LGPLv3 וזה לא עומד להשתנות.
שוחררה גרסה 0.99.5 של CppCMS שמכילה כלי חדש למניעת XSS.
התכונה הבולטת שנכנסה לגרסה זו היא למעשה פילטר מניעת XSS שמבוסס על "רשימה־לבנה" וביצוע בדיקות רבות על HTML שמתקבל מהמשתמש. כלי כזה יאפשר שילוב בטוח של עורכי טקסט עשירים כמו TinyMCE אפליקציות מבוססות CppCMS.
כמובן שזה כלי חדש ודורש review ובדיקה של זמן.
כרגע המסנן מופעל במערכת ויקי של CppCMS ואתם מוזמנים לנסות ולהכניס קוד זדוני בארגז החול של הויקי ולעשות Code-Review לפילטר עצמו xss.cpp ו־xss.h.
אם אתם מצליחים לעקוף את פילטר ה־XSS המופעל בויקי, אנא דווחו לי באופן מידי
עדכון: בטעות "ארגז החול" היה סגור לאורחים - זה תוקן, כל אחד יכול לערוך אותו ללא הרשמה
מפגש עולמות - או מדוע כדי לבצע פקודת SQL אתה לא אמור להוריד כלי של 150MB.
אחת הבעיות הגדולות ביותר של מפתח הרגיל לעבוד בסביבת לינוקס ומפתח הרגיל לעבוד בסביבת חלונות הוא לא השינוי של שפות, תוכנה או ה־API הוא שינוי של תפיסת עולם שלמה. לפיתוח חוצה פלטפורמה יש מספיק כלים טובים ונוחים להתמודד איתם:
- לפיתוח ממשקים יש לך כלים מצויינים כמו Qt - שגם בעולם חלונות הופכים למובילים. כמובן גם כלים כמו Java Swing או Java SWT הם מעולים.
- לפיתוח web - כמעט כל דבר: PHP, Rails, Django, JSP/Java אפילו Asp.Net הופך ליותר זמין בזכות (או באשמתה תלוי איך רואים) של Mono.
- פיתוח רכיבי תשתית ב־C++ עם כלים כמו Boost הופכים לשקופים, וכמובן אסור לשכוח את Java, Python, Perl ושפות רבות אחרות שנותנות SDK עשיר חוצה פלטפורמה.
אבל הבעיה עדיין נשארת פתוחה - אם אתה לא מתאמץ ולא מכיר את שני העולמות - קשה לפתח משהו שהוא ייראה טבעי ונוח בשני העולמות.
הסיפור
תוך כדי פיתוח CppDB ובניית תמיכה ב־ODBC רציתי לבדוק עבודה מול MS SQL Server בגלל הגישה "המיוחדת" שלו ל־Unicode. מה יותר פשוט:
- יש מכונה וירטואלית מוכנה.
- יש גרסת SQL Server Express 2008 חינמית.
- יש odbcunix ו־freetds מותקנים.
לא אמור להיות מסובך. מתוך אפשרויות ההתקנה בחרתי את הקטנה והפשוטה ביותר - להתקין רק את המנוע ששוקל רק 70MB בלי תוספות משוכללות כמו Management Studio ודברים מיותרים אחרים.
הורדתי, התקנתי - תוך כדי התקנה הגדרתי משתמש ניהול - בסה"כ next->next->next וזה מוכן. אחר כך הגדרתי תקשורת מעל TCP/IP הגדרתי קישוריות מ־VirtualBox ו־host הגדרתי ODBC מתחבר... לא מצליח לבצע login.
אחרי חקירה קצרה ובדיקת Event Log מתברר השמשתמש שהגדרתי בהתקנה לא מוגדר. להגדיר משתמש זה אמור להיות די פשוט (בסה"כ להריץ פקודת SQL פשוטה) אבל נפלתי במלכוד 22:
- כדי להגדיר משתמש חדש אני צריך קישוריות לבסיס הנתונים.
- כדי שתהיה לי קישוריות לבסיס הנתונים אני צריך משתמש.
אחרי חיפושים ובדיקות הבנתי שעדיין יש משתמש XP שאמור להיות מסוגל לבצע login ואפילו הצלחתי לבצע login ולהריץ שאילת עם איזשהו כלי import המגיע עם SQL Server. כל מה שנותר לי זה להתחבר לבסיס הנתונים עם משתמש XP של מתוך המכונה עצמה ולבצע login... השאלה כיצד?
הכלי שאני מכיר להתחברות הוא sql management studio ששוקל 150MB... אבל אני צריך להריד סה"כ פקודה או שניים? חייב להיות אישזהו כלי שאפשר להריץ בשורת פקודות כדי להתחבר לשרת SQL ולהריץ פקודה.
מכיוון שאני לא מכיר את Microsoft SQL Server מספיק, שאלתי שאלה ב־Serverfault:
כיצד להגדיר משתמש בשרת SQL ללא שימוש ב-Management Studio.
קיבלתי תשובה, אכן היה כלי כמו שחיפשתי, סידרתי login והצלחתי להתחבר לשרת ללא בעיות מיוחדות.
אבל זה לא מה שמעניין בסיפור, מה שמעניין זה הערות שקיבלתי על השאלה שלי: הנה דוגמאות:
Top rated(3 votes)
> It seems silly to not use
> the purpose built tools that
> come packaged with the product
> just to save a few hundred MB
Another one, very good:
> As someone who manages numerous SQL
> Server instances from Sql 2000 - 2008,
> creating a VM to throw XP (at least)
> just to run SSMS makes sense. SSMS is your
> friend..not the enemy you're making it out to be..
כיצד להסביר לאנשים האלה, שזה לא נראה לי הגיוני להוריד 150MB כדי לבצע שתי פקודות?
הבעיה במעבר בין שני העולמות זה לא כלים, זה לא שפות זה סוג החשיבה; וזה המחסום הגדול במעבר בין עולמות.
אני רואה מפתחי חלונות לא מבינים בצורך להיכנס לשורת פקודות, לא מבינים כיצד אפשר לפתח ללא IDE או לעבוד מול SQL ללא כלי משוכלל. מצד שני אני רואה את עצמי ומפתחי לינוקס אחרים נגעלים בכל פעם מחדש מה"כלים המשוכללים" שלא עובדים כמו שצריך שעושים דברים לא ברורים מאחורי הקלעים ולא מאפשרים לא לדבג בעיות בצורה שקופה, כלים שאי אפשר להריץ אותם מתוך סקריפט ועוד.
האמת... לא נכון, מרבית כלי Microsoft באים עם כלי שורת פקודות. למשל ,אני עובד הרבה יותר עם CMake+NMake+CL מאשר עם IDE של Visual C++ ואני מבין הרבה יותר טוב איך הדברים עובדים. רק שבעולם ההוא זה לא מקובל.
לך תבין! בגלל זה המעבר בין העולמות הוא הרבה מעבר למעבר בין Posix API ל־Win32 API הרבה מעבר למעבר מ־cl ל־gcc ולהפך, לעבר מ־Visual Studio ל־KDevelop או מעבר בין דיאלקט SQL של MS SQL לבין זה של PostgreSQL או MySQL.
הבעיה היא הרבה יותר עמוקה שאני לא חושב שבלי ניסיון של שנים אפשר לפצות עליה.
קישוריות לבסיסי נתונים מ־C++
לאחרונה אני הייתי מאוד לא מרוצה מעבודה עם libdbi בתור ספריית הקישוריות לבסיסי נתונים וגם לא הצלחתי להתחבר ל־SOCI ממספר סיבות נוספות.
הספריה הראשונה libdbi לא תומכת בכלל ב־Prepared Statements, יש לה לא מעט בעיות בגישה לטעינה של מודולים, הספריה השניה soci לא מי יודע מה מוצלחת מבחינת הגישה שלה לפיתוח, בפרט, סירוב עקבי שלא לתמוך ב־Last-Insert-Id או עבודה קצת עקומה עם prepared-statements ומחזור שחרור גרסאות מאוד ארוך (שבפועל דורש ממך לעבוד עם גרסת git).
אז מתוך ניסיון עבודה עם שתי הספריות האלה ניסיון מסוים בעבודה עם JDBC החלטתי לבנות משהו חילופי כאשר הדרישה העיקרית היא:
- לתמוך בצורה שקופה ב־prepared-statements וגם ליצור cache שלהם כך שתהליך ההכנה שלהם יתבצע בפועל פעם אחת בלבד בצורה שקופה.
- לתמוך ב־connection pooling בצורה שקופה ונוחה.
- אפשרות לטעון מודולים של בסיסי הנתונים בצורה דינאמית וגם לקשר אותם בצורה סטטית לצורך הפצה נוחה.
- גמישות מבחינת בחירה של statement רגיל ו־prepared.
- מהירות
- תמיכה מלאה ב־postgresql, mysql וב־sqlite3.
- תמיכה במספר גבוהה ככל האפשר של בסיסי הנתונים דרך מערכת קישוריות חילופית (odbc).
כך נוצרה ספריית cppdb הזמינה תחת LGPLv3 (קישור חילופי).
כמובן רבים יאשימו אותי בהמצאת גלגל מחדש, אבל למעשה יצרתי משהו מאוד ייחודי שלא קיים במרבית ספריות הקישוריות הקיימות (ולא רק ב־C++) - הסיבה העיקרית זאת הנוחות העבודה עם prepared-statements והשמירה האוטומטית שלהם לצורך השימוש החוזר שנותנת תוספת ביצועים של עשרות אחוזים.
בנוסף שחררתי גם עדכון ל־dbixx (המעטפת של libdbi) המביאה מספר תיקונים ושיפורים יחד עם ההחלטה להזניח את הפיתוח שלה תוך כשנה לטובת ה־cppdb.