מנפה קודי TOTP / 2FA

הפקה וניפוי של קודי TOTP / 2FA: הגזירה המלאה לפי RFC 6238, אימות עם חלון סחיפה, ופירסור otpauth:// — הכול בדפדפן שלך.

זמן

הזינו סוד כדי לראות קוד.

otpauth:// URI לתצורה הזו
otpauth://totp/user%40example.com?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&period=30

מה באמת הן שש הספרות

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

‏TOTP (‏RFC 6238) הוא שכבה דקה מעל מנגנון ישן יותר, HOTP (‏RFC 4226). ‏HOTP הופך סוד ומונה לקוד; ‏TOTP הוא פשוט HOTP כשהמונה מוגדר למספר צעדי הזמן מאז ראשית זמן Unix. זה כל הרעיון: לחלק את זמן Unix הנוכחי באורך הצעד (30 שניות כברירת מחדל) ולהזין את התוצאה ל-HOTP. הכלי הזה מציג כל שלב בחישוב, כי כשקוד לא עובר אימות, התשובה כמעט תמיד גלויה איפשהו בגזירה.

הגזירה, צעד אחר צעד

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

  • המונה. קחו את זמן Unix בשניות, החסירו את T0 ‏(0 בכל פריסה אמיתית), חלקו במחזור ועגלו כלפי מטה. בצעדים של 30 שניות, כל רגע באותה חצי-דקה נותן את אותו מונה, ולכן קוד מחזיק כמה שהוא מחזיק.
  • ה-HMAC. כתבו את המונה כ-8 בייטים בסדר big-endian וחשבו HMAC(סוד, מונה) עם הגיבוב הנבחר — SHA-1 כמעט בכל אפליקציית אימות. זה מפיק תקציר של 20 בייט ל-SHA-1 ‏(32 ל-SHA-256, ‏64 ל-SHA-512).
  • ההיסט. קחו את ארבע הסיביות התחתונות של הבייט האחרון בתקציר. זה מספר בין 0 ל-15, והוא אומר היכן בתקציר לקרוא — קיטום דינמי, כך שאותו סוד לא משתמש תמיד באותם בייטים.
  • הערך בן 31 הסיביות. קראו ארבעה בייטים החל מההיסט, והסתירו את הסיבית העליונה (כדי להימנע מבלבול סימן). נשאר מספר שלם בן 31 סיביות.
  • הקוד. קחו את המספר הזה מודולו 10^ספרות ורפדו באפסים משמאל. שש ספרות היא הבחירה כמעט-אוניברסלית; שבע ושמונה קיימות ומותרות.

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

למה קוד לא תואם — שלוש הסיבות הרגילות

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

  • הסוד נקרא בפורמט שגוי. סוד של אפליקציית אימות הוא Base32, אבל אותם תווים הנקראים כ-hex — או סוד שהיה למעשה hex הנקרא כ-Base32 — מפיקים בייטים שונים לגמרי וקוד שונה לגמרי. החליפו את מתג הפורמט וראו איזה נותן את הקוד שאתם מצפים לו.
  • פרמטר שונה. ברירת המחדל המכריעה היא HMAC-SHA-1, ‏6 ספרות, מחזור של 30 שניות. שרת שמשתמש ב-SHA-256, או 8 ספרות, או צעד של 60 שניות, יתנגש עם אפליקציה שנשארה על ברירות המחדל. ה-otpauth:// URI נושא את כל השלושה, ולכן סריקת QR מקבלת אותם נכון והקלדת סוד ביד לעיתים קרובות לא.
  • השעונים סחפו. ‏TOTP מניח ששני הצדדים מסכימים על הזמן. אם שעון של טלפון ממהר בדקה, הקוד שלו דקה לפני של השרת. בשביל זה חלון הסחיפה: אימות קוד מול הצעדים משני צדי העכשיו אומר לא רק אם יש התאמה אלא כמה השעון סוטה.

‏RFC 6238 ממליץ על חלון אימות של צעד אחד לכל היותר בכל צד — מספיק כדי לספוג סחיפת שעון רגילה ואת מרוץ רגע-הגלגול, בלי להרחיב את מרחב הניחוש יותר מהנדרש. הכלי הזה מוגדר כברירת מחדל ל-±1 ומאפשר להרחיב אותו בזמן ניפוי.

סודות, Base32 וה-otpauth:// URI

הסוד משותף פעם אחת, בהתקנה, והכול אחר כך נגזר ממנו. אפליקציות אימות מקודדות אותו ב-Base32 (‏RFC 4648) — האלפבית A–Z ו-2–7, שנמנע מהתווים שקל לבלבל ושורד הדפסה מתחת ל-QR. הכלי הזה קורא Base32 כברירת מחדל, מתעלם מהרווחים שאפליקציות מוסיפות לקריאוּת ומאותיות גדולות/קטנות, וגם מקבל hex כדי שתוכלו לשחזר את וקטורי הבדיקה של RFC 6238, שה-seed שלהם נתון כבייטים גולמיים.

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

otpauth://totp/GitHub:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=GitHub&algorithm=SHA1&digits=6&period=30

רק הסוג totp מתקבל. ‏otpauth://hotp URI נושא מונה במקום מחזור, והתייחסות אליו כ-TOTP הייתה מפיקה בשקט קודים שגויים — ולכן הוא נדחה במקום לנחש.

אלגוריתם, ספרות ומחזור

‏RFC 6238 מתיר HMAC-SHA-1, ‏SHA-256 או SHA-512, שש עד שמונה ספרות, וכל אורך צעד. בפועל העולם התכנס ל-SHA-1, שש ספרות ושלושים שניות, ורוב אפליקציות האימות מממשות רק את הצירוף הזה — כך ששרת שבוחר משהו אחר צריך לקוות שאפליקציית המשתמש עוקבת, ורבות לא. הבחירה הבטוחה לתאימות היא המשעממת.

כדאי להתייחס לשאלת ה-SHA-1 ישירות, כי כלי הגיבוב באתר הזה מסמן את SHA-1 כשבור. שני המשפטים נכונים. ‏SHA-1 לא שמיש לחתימות דיגיטליות כי תוקפים יכולים לייצר התנגשויות — שני מסמכים עם אותו גיבוב. ‏TOTP לא נשען על התכונה הזו: האבטחה שלו מגיעה ממפתח הסוד בתוך ה-HMAC, לא מכך שהגיבוב עמיד להתנגשויות, ו-HMAC-SHA-1 נשאר איתן. שימוש ב-SHA-256 כאן הגיוני אבל קונה מעט, ועולה בתאימות עם אפליקציות שעושות רק SHA-1.

מה הכלי הזה מגן ומה לא

הכול כאן רץ בדפדפן שלכם. ה-HMAC מחושב עם Web Crypto API על המכשיר שלכם, אותו פרימיטיב שכלי הגיבוב וה-HMAC משתמשים בו, ושום דבר שאתם מקלידים — סוד, קוד או otpauth URI — לא מועלה, נשמר או נרשם. זו תכונה של הקוד שרץ בצד-לקוח, לא הבטחה שצריך לקבל באמון.

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

שאלות נפוצות

האם הסוד שלי נשלח לשרת?
לא. הקוד מחושב בדפדפן שלכם עם Web Crypto API, ושום דבר שאתם מקלידים לא מועלה או נרשם. מכיוון שסוד TOTP הוא גורם שני, עדיין היזהרו בהדבקת סוד ייצור — הוא עלול לעבור דרך הלוח והיסטוריית הדפדפן כמו כל טקסט אחר.
למה הקוד שלי לא תואם לאפליקציית האימות?
כמעט תמיד אחד משלושה: הסוד נקרא בפורמט שגוי (‏Base32 מול hex), פרמטר שונה מברירות המחדל (רוב האפליקציות הן SHA-1, ‏6 ספרות, מחזור 30 שניות), או ששעון המכשיר סחף. פאנל הגזירה מבודד את השניים הראשונים, ואימות עם חלון סחיפה ± חושף את השלישי.
מה ההבדל בין TOTP ל-HOTP?
‏HOTP (‏RFC 4226) מחשב קוד מסוד וממונה שגדל בכל שימוש. ‏TOTP (‏RFC 6238) הוא אותו מבנה כשהמונה מוגדר למספר צעדי הזמן מאז ראשית זמן Unix, כך שהקוד משתנה עם השעון ולא עם לחיצת כפתור. ‏TOTP הוא מה שאפליקציות אימות משתמשות בו.
למה SHA-1 הוא ברירת המחדל אם הוא שבור במקום אחר?
‏SHA-1 שבור לחתימות כי אפשר לבנות התנגשויות, אבל HMAC — שעליו TOTP בנוי — לא תלוי בעמידות להתנגשויות; האבטחה שלו נשענת על מפתח הסוד. ‏HMAC-SHA-1 איתן, והוא האלגוריתם היחיד שרבות מאפליקציות האימות מממשות, אז הוא גם הבטוח וגם ברירת המחדל התואמת.
אפשר לקבע את הקוד לזמן מסוים?
כן. החליפו את הזמן מ-חי ל-מקובע והזינו חותמת זמן Unix. הקוד אז נשאר סטטי, וכך משחזרים וקטור בדיקה שפורסם — RFC 6238 נותן ערכים בזמנים כמו 59 ו-1111111109 — או בודקים איזה קוד היה תקף ברגע עבר.
כמה גדול צריך להיות חלון הסחיפה?
‏RFC 6238 ממליץ על צעד אחד לכל היותר בכל צד, וזו ברירת המחדל של הכלי. חלון רחב יותר סובל שעון סחוף יותר אבל גם מגדיל את קבוצת הקודים ששרת יקבל, אז זה איזון; ‏±1 הוא האיזון התקני.
בשביל מה הספרות והמחזור?
הספרות הן כמה ספרות יש בקוד — שש כמעט בכל מקום, שבע או שמונה כשירות רוצה מעט יותר חוזק. המחזור הוא כמה שניות קוד נשאר תקף, שלושים כברירת מחדל. שניהם נישאים ב-otpauth:// URI, ושניהם חייבים להתאים בשני הצדדים אחרת הקודים לא יסכימו.