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