איך לייבא שליחות טפסים ציבוריות לרשת פרטית
עקבו אחרי שליחה ציבורית אחת מרשומת הקליטה אל המייבא הפרטי, והשאירו אימות, הרשאות וטיפול בניסיונות חוזרים בצד הנכון.
טופס ציבורי שלעולם אינו מדבר עם הרשת הפרטית עדיין מייצר נתונים שהרשת הפרטית חייבת לשפוט. המנהרה משנה רק מי מחייג למי. כל מה שאחרי ההורדה הוא החלטת ייבוא, והיא שייכת לצד הפרטי. הסיור הזה עוקב אחרי שליחה אחת מהדפדפן עד לרשומה פנימית מחייבת.
התחילו במקום שבו השליחה נוחתת
הדפדפן שולח לנקודת קצה ציבורית, שכותבת שורה למאגר קליטה מבוקר ומחזירה דבר מלבד אישור. המאגר הזה הוא נקודת המסירה, והוא אמור להיות הדבר היחיד שהשכבה הציבורית יכולה לכתוב אליו. שמרו שם את המטען הגולמי ללא שינוי, יחד עם זמן ההגעה ומזהה רשומה יציב.
לאחר מכן עובד פרטי מושך שורות ממתינות דרך המנהרה ומחליט מה לעשות בכל אחת. הוא פועל תחת זהות משלו, וזה הנושא של הסעיף הבא.
curl --silent --fail \
--cert /etc/importer/client.crt --key /etc/importer/client.key \
"https://intake.corp.internal/api/pending?limit=20" \
-o /var/lib/importer/pending.json
תנו למייבא רק את הסמכות שהוא צריך
תהליך האינטרנט הציבורי והזהות שכותבת ליישום הפנימי צריכים להיות שני גורמים שונים. שרת ציבורי אינו זקוק לניהול פנימי רק משום שעליו למסור נתוני טופס, וחשבון משותף אחד לשני הצדדים הופך כל תקלה באינטרנט לכתיבה פנימית. הנפיקו לעובד הרשאה משלו, הגבילו אותה לפעולת הייבוא האחת, ותעדו איזה גורם ביצע כל ייבוא. ההפרדה הזו היא מה שהופך את גבול המנהרה למשמעותי ולא לקישוט.
הגבילו גם מאיזה מקור העובד רשאי לקרוא. אם המימוש משתמש בתור או בשירות העברה, השירות הזה שומר על האימות ומדיניות הגישה שלו, מפני שה-VPN אינו מאמת דבר בתוך המטען.
פונקציה קצרת חיים אינה פטורה מאותה בחינה. כל עוד היא פועלת, מיקומה ברשת והרשאותיה עדיין מעניקים סמכות, ותוחלת חיים קצרה רק מצמצמת את החלון. תוחלת חיים אינה תחליף להחלטה אילו פעולות הזהות רשאית לבצע.
אמתו לפני שמשהו פנימי משתנה
שדות של טפסים ציבוריים הם טקסט בשליטת התוקף עד שיוכח אחרת, וההנחיות של OWASP לאימות קלט מונות זרמי backend בין המקורות שאינם מהימנים בדיוק מהסיבה הזו. העברה מוצפנת אומרת שהבתים הגיעו שלמים, ולא שהם מתארים בקשה מורשית. נתחו ואמתו לפני כל שלב בעל הרשאה, כדי ששורה רעה לא תגיע לעולם לנתיב קוד שיכול לפעול.
הגדירו את השדות המותרים, את הפורמטים שלהם, את הגדלים שלהם ואת כללי העסק שעליהם להתקיים. תאריך יכול להיות מעוצב היטב ועדיין שגוי עבור הפעולה המבוקשת, ומטען שמציין חשבון פנימי או מצב אישור לא צריך להיות מסוגל להעניק לעצמו אף אחד מהם.
שלחו שורות שנדחו לתוצאת סקירה במקום לנחש תיקון או להעביר אותן למעטפת או לממשק מסד נתונים גולמי. תעדו את מזהה הרשומה ואת הכלל שנכשל, ולא כל שדה שהמגיש הקליד.
צרו נקודת ניסיון חוזר בפעולה אחת
אם הרשומה submission-1042 נמשכת פעמיים מפני שהאישור הראשון אבד, העובד זקוק לדרך עמידה לזהות את רשומת המקור ואת תוצאתה המחייבת. לוח זמנים שמריץ את העבודה פעם אחת אינו מוכיח שכל שורה יושמה פעם אחת. מסירה כפולה היא מצב רגיל, ולכן התכנון חייב לספוג אותה.
השתמשו במנגנון העסקאות וטיפול הכפילויות של היישום הפנימי עצמו, ושמרו את מזהה המקור, התוצאה והאישור ברצף אחד עקבי. אשרו רק לאחר שהפעולה המיועדת נקבעה או הוקצתה באופן עמיד, ואל תמחקו את שורת הקליטה רק מפני שהבתים הורדו.
ואז הוכיחו זאת בשלושה קבצי בדיקה: שורה תקפה, שורה פגומה, ואותו מזהה מקור מבוקר שנמסר פעמיים. כל אחד מהם עובר דרך אותה נקודת קצה שהעובד משתמש בה.
for f in fixtures/valid-submission.json fixtures/bad-date.json; do
curl --silent --fail --cert /etc/importer/client.crt \
-X POST --data @"$f" https://intake.corp.internal/api/records
done
curl --silent --fail --cert /etc/importer/client.crt \
-X POST --data @fixtures/valid-submission.json https://intake.corp.internal/api/records
שתי השורות הראשונות חייבות להסתיים במצבים פנימיים שונים, והשלישית חייבת להחזיר את המזהה שכבר נקבע לאותה רשומת מקור במקום ליצור שני. כל דבר אחר אומר שהייבוא עדיין אינו ניתן לחזרה.