הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

בעיה של עומס

23/05/2019

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

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

במקום לגרד עוד חצי שעה ביום שווה להתאמץ ולהוריד משימה או שתיים. זמן הלימוד ימצא מהר מאוד את הדרך למלא את הוואקום.

מהי בעיית Key Reuse בעבודה עם מצפין זרם

22/05/2019

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

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

מימוש מצפין זרם פופולרי (ולא הכי מאובטח) נקרא RC4 והקוד שלו בפייתון הוא בסך הכל:

def rc4(data, key):
    """RC4 encryption and decryption method."""
    S, j, out = list(range(256)), 0, []

    for i in range(256):
        j = (j + S[i] + ord(key[i % len(key)])) % 256
        S[i], S[j] = S[j], S[i]

    i = j = 0
    for ch in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(chr(ord(ch) ^ S[(S[i] + S[j]) % 256]))

    return "".join(out)

הטעות הכי גדולה של אנשים שמשתמשים במצפין זרם נקראת Key Reuse. זה אומר להשתמש באותו Key Stream כדי להצפין מספר הודעות. ולמה זה רע? כי בגלל הטבע של XOR במצב כזה המפתחות "מתבטלים". במתמטיקה זה אומר ש:

C1 = Message1 ^ Key
C2 = Message2 ^ Key
=>

C1 ^ C2 = M1 ^ Key ^ M2 ^ Key
C1 ^ C2 = M1 ^ M2

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

אז הנה דוגמא בשפת פייתון של תוכנית שמצפינה שתי הודעות ושומרת 3 קבצים: קובץ אחד מכיל את ההודעה הראשונה מוצפנת, קובץ שני את ההודעה השניה והקובץ השלישי את ה XOR בין שני הקבצים המוצפנים:

from rc4 import rc4

enc1 = rc4('hello world', 'secret')
enc2 = rc4('\x00' * 10, 'secret')

with open('msg1.bin', 'w') as f:
    f.write(enc1)

with open('msg2.bin', 'w') as f:
    f.write(enc2)

with open('msg_xor.bin', 'w') as f:
    xor_enc = ''.join([chr(ord(a) ^ ord(b)) for a,b in zip(enc1,enc2)])
    f.write(xor_enc)

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

$ xxd msg1.bin
00000000: c285 53c2 be70 c3ad c284 c2a1 c389 40c2  ..S..p........@.
00000010: a7c3 9f                                  ...

$ xxd msg2.bin 
00000000: c3ad 36c3 921c c282 c2a4 c396 c2a6 32c3  ..6...........2.
00000010: 8b                                       .

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

$ xxd msg_xor.bin 
00000000: 6865 6c6c 6f20 776f 726c                 hello worl

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

תתפלאו לשמוע שהפיתרון במצבים כאלה הוא מאוד קל - פשוט צריך להוסיף ערך ייחודי למפתח כדי שה Key Stream יהיה שונה לכל הודעה שנצפין. הנה התוכנית המתוקנת שלנו:

from rc4 import rc4

enc1 = rc4('hello world', 'secret1')
enc2 = rc4('\x00' * 10, 'secret2')

with open('msg1.bin', 'w') as f:
    f.write(enc1)

with open('msg2.bin', 'w') as f:
    f.write(enc2)

with open('msg_xor.bin', 'w') as f:
    xor_enc = ''.join([chr(ord(a) ^ ord(b)) for a,b in zip(enc1,enc2)])
    f.write(xor_enc)

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

$ xxd msg_xor.bin 
00000000: c398 6ac2 9070 0b0e 3257 c3bb 5d         ..j..p..2W..]

שאלות מראיונות עבודה - מיון רשימה

21/05/2019

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

https://www.hackerrank.com/challenges/new-year-chaos/problem

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

לדוגמא אם אנחנו מתחילים עם הרשימה:

[2, 1, 5, 3, 4]

נצטרך לפחות 3 פעולות החלפה כדי למיין אותה:

  1. קודם נחליף את ה-1 וה-2

  2. אחרי זה נחליף את ה-3 וה-5

  3. אחרי זה נחליף את ה-4 וה-5 (ליד ה-4 היה פעם 3, אבל אחרי ההחלפה הקודמת יש שם עכשיו 5).

ובשביל לסבך קצת את החיים יש גם תוספת קטנה - כל פעם שמחליפים שני מספרים אנחנו רושמים את המספר השמאלי ביניהם בצד ברשימת ה"עוקפים" (כי בשביל להגיע למצב המבולגן הוא היה צריך לעקוף את המספר שמימינו). אם אחד המספרים "עקף" יותר מפעמיים עלינו להפסיק ולהדפיס את הפלט "Too chaotic".

המשך קריאה

העתקת קוד ואבטחת מידע

20/05/2019

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

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

https://shasaurabh.blogspot.com/2017/07/virtual-machine-detection-techniques.html

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

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

סט-אפים

19/05/2019

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

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

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

אני לא ממליץ על הגישה הזאת.

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

איך אתרים נפרצים?

18/05/2019

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

  1. באגים טפשיים - למשל מתכנת שלא בדק קלט ובגלל זה האתר פגיע ל SQL Injection, או מתכנתת ששכחה לוודא שסכום משיכה בחשבון הוא מספר חיובי וחיסרה אותו מהסכום הקיים (מה שיוצא מצחיק כשאתה מנסה למשוך מינוס 50 שקל).

  2. באגים חכמים - באגים חכמים זה דברים שהרבה יותר קשה למצוא והרבה יותר קשה לתקן. לפעמים זה באג טפשי שעטוף בשכבות-שכבות של הגנה כך שקשה מאוד לנצל אותו, ולפעמים אלה באגים שצריך מומחיות מאוד גבוהה בשביל להבין למה זה שבור ואיך לנצל את זה לרעה. בשביל למצוא באג חכם חוקרי אבטחה משתמשים בכלי Reverse Engineering מתוחכמים ומשקיעים הרבה מאוד זמן בחיפוש. ניצול הבאגים האלה יכול להוביל להשתלטות על המערכת כולה בלי שבעל האתר בכלל שם לב שיש לו אורח.

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

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

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

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

https://www.tocode.co.il/workshops/76

נתראה ינון

עיבוד נתונים מקבילי עם תבנית Producer/Consumer

17/05/2019

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

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

תבנית Producer/Consumer עוזרת לנו להתמודד עם עיבוד מקבילי של מידע ומומלצת בתרחישים כאלה ורבים נוספים. נמשיך לראות איך זה בנוי.

המשך קריאה

אינטואיציה

16/05/2019

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

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

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

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

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

  3. לכתוב "יומן אינטואיציה" שאומר שאם נראה לכם שתבנית מסוימת הולכת להצליח (או להיכשל) אז תכתבו את זה גם בקוד וגם ביומן. אחרי כמה חודשים חיזרו למה שרשמתם ובידקו אם צדקתם.

  4. לקחת פרויקט קוד פתוח ולנסות לנחש איך הם התמודדו עם בעיה מסוימת (למשל איך gon מעביר את המשתנים מריילס ל JS). אחרי זה מסתכלים בקוד שלהם ורואים אם צדקתם.

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

יש לכם רעיונות נוספים? מוזמנים לשתף בתגובות.

תואר אקדמי והייטק

15/05/2019

שיחה מקרית בקורס היום עזרה לי להבין שבכניסה להייטק (ולפעמים גם די עמוק בפנים) קשה לראות את הערך של תואר אקדמי. הרבה אנשים מרגישים שאפשר להגיע די רחוק גם בלעדיו או שאם את כבר כמה שנים בתעשיה אז אין טעם להתחיל עכשיו תואר. אז בשביל להוכיח לעצמי (ולכם) שבארץ התואר כן חשוב הלכתי לגוגל וחיפשתי פרופילי לינקדאין ישראלים של VP R&D, לא משנה מאיזה חברה. חשבתי שנוכל להעיף מבט יחד מי הם ולמי מהם יש תואר אקדמי. הנה הרשימה שגוגל נתן לי:

  1. Karin Moscovici, VP R&D at Riskified - בוגרת מדעי המחשב מהאוניברסיטה העברית.

  2. Gil Wasserman, VP R&D at Guesty - בוגר פיזיקה מאוניברסיטת תל אביב.

  3. Leon Gendler, VP R&D, Sisense - בוגר מדעי המחשב מאוניברסיטת תל אביב.

  4. Ohad Stauber, VP R&D at OSR - מהנדס חומרה בוגר הטכניון.

  5. Lior Leiba, VP R&D at Augury - בוגר מדעי המחשב מהטכניון.

  6. Avi Etzioni, VP R&D at Planck - בוגר ביואינפורמטיקה מאוניברסיטת תל אביב

  7. Shahar Elias, VP R&D at WalkMe - בוגר מדעי המחשב מהמכללה למנהל.

  8. Amir Shaked, VP R&D at PerimeterX - בוגר פיזיקה מאוניברסיטת תל אביב

  9. Ronny Ahituv, VP of R&D at SkyWatch - בוגר מתמטיקה ומדעי המחשב מהעברית

  10. Yaron Gueta, VP R&D at Glassbox Digital - בוגר מדעי המחשב מהאקדמית תל אביב יפו

לא סיננתי ולא חיפשתי במיוחד. אתם יכולים לחזור על החיפוש גוגל שעשיתי. אגב לא הדבקתי לפה אבל בשביל המשחק המשכתי ל-10 תוצאות הבאות ובהן היה רק סמכנ"ל פיתוח אחד עבורו לא הופיע תואר אקדמי בלינקדאין (ניר בצלאל מ Moovit). בכל מקרה וגם אם נתבסס רק על לינקדאין יש לנו 19 מ-20 מנהלי פיתוח בוגרי תואר.

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