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

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

איך לעבור שרת ולהשאיר את האתר באוויר

28/05/2019

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

המשך קריאה

חמש דקות על Bitbucket Pipelines

27/05/2019

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

המשך קריאה

כמה זמן זה ייקח?

26/05/2019

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

שלוש בעיות עם השאלה הזאת-

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

  2. לאנשים שונים נקודת מוצא שונה (וגם את זה בית ספר מטאטא יופי מתחת לשטיח).

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

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

פרילאנסרים? תתחילו בלהבין מה אתם מוכרים

25/05/2019

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

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

וזה לא שלא היה לי תיק עבודות, הבעיה היתה במה שהיה בתיק.

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

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

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

בעיה של עומס

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 או מה שלא בחרתם ללמוד.