IP whitelisting לא עובד: כתובות מוחלפות וחסימות שגויות
פרוקסי הפוך או מאזן עומסים לפני שרת האינטרנט שובר את הסינון לפי ip — וזו הסיבה הנפוצה ביותר לכך ש-IP whitelisting מתנהג בצורה בלתי צפויה.
את החיבור לאפליקציה יוצר מתווך, ולכן בכללי הגישה במקום הלקוח מופיעה הכתובת שמאחורי הפרוקסי: אותה כתובת עבור כל המבקרים — כתובת השער או מאזן העומסים.
ההשלכות סימטריות ושתיהן רעות. רשימת ההיתר או מכניסה את כולם בלי הבחנה, כי כל בקשה מגיעה מכתובת «מהימנה» אחת, או מסרבת לכולם — אם המתווך אינו ברשימה.
רשימת החסימה נוקשה יותר: כשחוסמים כתובת אחת, חוסמים את הגישה לכל מאגר לקוחות שמאחורי מאזן העומסים הזה, וחסימה שגויה של לקוח הופכת להשבתה של כל האתר.
השכבה השנייה של הבעיה — אמון בכותרים. הלקוח מוסיף כותרת עם כתובת באופן ידני, ואם השרת מקבל אותה ללא בדיקה, כתובת ip מוחלפת עוקפת גם את רשימת ההיתר וגם את רשימת החסימה.
הכלל כאן אחד: אנו נותנים אמון לכותרים רק ממתווכים מוכרים ומפרקים את השרשרת מהסוף — הכתובת הראשונה שייכת ללקוח רק כאשר כל הקודמות נכללות בטווחי הרשת המהימנים.
לכן הסינון לפי ip נבנה לא על מה שנראה בסוקט, אלא על כתובת הלקוח המשוחזרת. בהמשך נפרק כיצד זה נסגר: אילו טווחים להכריז כמהימנים, באיזה סדר לקרוא את השרשרת במספר קפיצות וכיצד לבדוק את המדיניות כך שהיא לא תכניס גורמים מיותרים ולא תחסום את אנשינו.
מה משתנה לאחר הטמעת סינון בפרימטר
כל עוד הסינון קיים רק במאזן העומסים, כתובת הלקוח האמיתית הולכת לאיבוד: ביומנים כל הבקשות מגיעות מכתובת הפרוקסי עצמו. כללים לפי מקור מתחילים לעבוד בצורה עיוורת — לגורם סירוב מגיעים משתמשים לגיטימיים מאחורי פרוקסי משותף, בעוד תעבורה לא רצויה עוברת.
זה מטופל ברמת הקונפיגורציה: פרוקסים מהימנים מפורטים במפורש, וכותרת עם הכתובת המקורית מתקבלת רק מהם — ב-nginx זה מוגדר באמצעות הנחיות מודול realip, ב-Apache — במנגנון דומה.
לאחר ההגדרה אנו מחשבים שלושה מדדים שמהם רואים מה השתנה בפרימטר.
- שיעור התראות שווא — בקשות שנחסמו על ידי כלל בעת מקור לגיטימי. אנו שומרים עליו מתחת לאחוז ומנתחים כל אירוע: הכלל מובהר, ולא מושבת כליל.
- זמן שחזור הגישה — אם הרשימה בכל זאת פגעה בעובד או בקבלן, הכתובת מוחזרת תוך דקות, ללא עריכת קונפיגורציה והפעלה מחדש של השירות.
- שיעור הבקשות עם מקור מזוהה כהלכה — לאחר ההגדרה שואף לשלם. על נתונים אלה מתבססים ניתוח אירועים, הגבלת קצב וחסימות ממוקדות.
האפקט מחזיק מעמד כל עוד הרשימות חיות. מונים על סירובים ועל שינויים ברשימות נותנים התראה בעת זינוק, ואחת לשבוע הרכב נבחן מחדש: כתובות מיושנות של קבלנים מוסרות, גישות זמניות נסגרות. שליטה במקורות התעבורה הופכת לתקנון, ולא להגדרה חד-פעמית.
IP whitelisting: רמות סינון התעבורה ומגבלותיהן
ניתן להפעיל כלל סינון במספר רמות: בחומת אש או מאזן עומסים, בפרוקסי הפוך, בשכבת סינון חיצונית ובאפליקציה עצמה. ככל שהכלל קרוב יותר למקור התעבורה, כך זול יותר לסנן אשפה, אך כך פחות הקשר זמין להחלטה: ברמות התחתונות נראית רק הכתובת, ולא הדומיין, הנתיב או חשבון המשתמש.
הצד השני — כללים במאזן העומסים אינם מבחינים בין שירותים מאחורי כתובת אחת, ולכן עבור אפליקציות שונות נדרשת לעתים שכבה משל עצמה ורשימת צמתים מהימנים משלה.
| רמה | מתי מתאימה | מגבלות |
|---|---|---|
| חומת אש, מאזן עומסים | יש צורך לחסום תעבורה לפני הגעתה לאפליקציה | נראית רק הכתובת: אין דומיין, נתיב ושיטה; רשימה אחת לכל השירותים |
| פרוקסי הפוך (nginx, Apache) | הכללים תלויים בדומיין או בנתיב, יש צורך בכתובת הלקוח האמיתית | דורש רשימת פרוקסים מהימנים, אחרת הכתובת ביומן מוחלפת |
| קוד האפליקציה | יש צורך בתפקיד, הרשאות והקשר הבקשה, תיעוד ביומן ביקורת | הבקשה כבר עברה את הרשת והתור, הכלל משוכפל בכל שירות |
| שכבת סינון חיצונית | התשתית משתנה, יש צורך ברשימה אחודה של צמתים מהימנים | תלות במעגל חיצוני ועיכוב באישור כללים |
הרמות אינן מחליפות זו את זו, אלא משלימות זו את זו: הרמה הרשתית חוסמת אשפה מובהקת, הפרוקסי מחזיר את כתובת הלקוח לאמיתית, והאפליקציה מקבלת החלטה לפי תפקידים.
המגבלה העיקרית של כל סינון — כתובת משותפת: מאחורי צומת אחד יכול לעמוד גם משרד שלם וגם מפעיל סלולרי, ולכן רשימת הצמתים המהימנים ברמה הרשתית אינה מבדילה בין משתמשים בפנים. מגבלות אלה מתקבלות במודע, ולא עוקפים אותן.
סדר ההטמעה של הסינון: מביקורת תעבורה ועד מסירה
סדר העבודות חשוב יותר מהכלי: כלל IP whitelisting שהופעל לפני מיפוי מקורות חוסם שותפים פעילים ושירותים פנימיים. לכן אנו הולכים ממפת התעבורה אל הקונפיגורציה, ובכל שלב משווים את התוצאה לבקשות אמיתיות, ולא להנחות.
-
מיפוי מקורות התעבורה. אוספים את כל נקודות הכניסה: אינטגרציות חיצוניות, כתובות משרדיות וענן, רובוטים שירותיים, ניטור. בפלט — רשימת תת-רשתות עם סימון «לחסום», «להגביל בקצב», «לא לגעת».
-
תרשים מעבר התעבורה. מפרקים את השרשרת עד לאפליקציה: היכן נמצא מאזן העומסים, כמה צמתים מעבירים בקשות בפרוקסי, מאיזו כותרת נקראת כתובת הלקוח. בלי זה המסנן רואה את כתובת הפרוקסי וחוסם או את כולם או אף אחד.
-
הגדרת כללי הגישה. מתארים את רשימות ההיתר והחסימה, ובנפרד סוגרים את האזורים המנהליים. פרוקסים מהימנים מוגדרים יחד עם הכללים — אחרת הכתובת המקורית מוחלפת כבר בצומת הראשון בדרך.
-
הרצה במצב תיעוד ביומן. מפעילים את הכללים כך שבקשות אסורות נרשמות ביומן אך מועברות. תוך מספר יממות נראית כל תמונת התראות השווא — מנקים אותן לפני האירוע, ולא אחריו.
-
בדיקה במעגל הפרודקשן. את מצב העבודה מפעילים תחילה על צומת אחד: משווים את שיעור הבקשות הנחסמות ואת זמינות השירותים. החזרה לאחור — עריכת קובץ קונפיגורציה אחד וטעינה מחדש.
-
מסירה לתפעול. מוסרים תרשים, קונפיגורציות, סדר הוספת כתובות חדשות וניתוח שגיאות אופייניות. התמיכה מבינה היכן לשנות את הרשימה, ולא מחפשת זאת ביומנים ברגע החסימה.
מה הלקוח מקבל לידיו: קונפיגורציות, תרשימים ותקנונים
אנו מוסרים את העבודה לא בתיאור «מה עשינו», אלא בסט ארטיפקטים: ניתן לבדוק אותם, להעביר לצוות אחר ולעדכן ללא מעורבותנו. להלן — הסט שנשאר אצלכם לאחר הטמעת IP whitelisting ב-nginx וב-Apache.
- קבצי קונפיגורציה — בלוקים מוכנים לשני השרתים: כללי
allow/deny, פרוקסים מהימנים לשחזור כתובת הלקוח האמיתית, סדר החלת ההנחיות ונקודות להכנסת רשומות חדשות. עם הערות לכל שורה, כדי שהתורנות תבצע את העריכה, ולא רק מחבר התרשים. - מדיניות גישה — אילו מעגלים סגורים בסינון, את מי מכניסים כברירת מחדל, מה עושים עם שאר התעבורה והיכן מסתיימת אחריות הרשת ומתחילה אחריות האפליקציה.
- תרשים מעבר הבקשות — המסלול מהלקוח דרך מאזן העומסים והפרוקסי עד האפליקציה: באיזה צומת נראית הכתובת האמיתית, היכן היא מוחלפת וכיצד לבדוק זאת בפקודה אחת.
- רשימות צמתים מהימנים — בנפרד לכל מעגל, עם בעל הרשומה, תאריך ההוספה וסימון האם ניתן להסירה.
- הוראות למשמרת תורנות — תרחישים לכל מקרה: להוסיף כתובת, להסיר חסימה, לוודא שהכלל הוחל, ומה לעשות במקרה של התראת שווא מחוץ לשעות העבודה.
- תקנון בחינה מחדש של כללים — תדירות הביקורת, מי מאשר את הרשומה, כיצד מתועדת סיבת החריגה ומתי הכתובת נמחקת אוטומטית.
הסט מיועד לכך שהכללים יתקיימו ללא המחבר: מהנדס המשמרת יכול להסביר מדוע כתובת מסוימת נמצאת ברשימה ומה יקרה אם יסירו אותה.
מקרה בוחן: כיצד הסרנו חסימות שגויות של לקוחות באיטרציה אחת
לפני: הכללים חסמו את הלא נכונים
הפורטל של הלקוח עמד מאחורי מאזן עומסים ורשת הפצת תוכן Cloudflare: לבקאנד כל הבקשות הגיעו מכתובות הפרימטר, ולא מכתובות המבקרים. כללי החסימה הופעלו על כתובת הפרימטר, ולחסימה נפלה ענף שלם של תעבורה של לקוח מהימן, ולא מקור האנומליה.
בשעות שיא התקבלו באופן עקבי 6–8% סירובים ללקוחות מהימנים, וכל מקרה כזה נראה כמו «האתר עובד, אבל לא אצלי».
ניתוח האירוע נתקע ביומנים: ברשומות עמדה אותה כתובת, היה צורך להצליב את הלוגים עם ייצוא מפאנל רשת ההפצה, ואיתור האשם ארך עד 40 דקות. שיעור הבקשות עם כתובת מקורית נכונה לא עלה על 12% — הסטטיסטיקה של הסינון לא הייתה ראויה לקבלת החלטות.
מה שינינו ומה נהיה
שחזרנו את הכתובת המקורית בשני הפרונטים: ב-nginx — מודול real_ip עם רשימה מפורשת של תת-רשתות מהימנות וכותרת X-Forwarded-For, ב-Apache — מודול RemoteIP עם פרוקסים מהימנים. את שרשרת הכותרות אנו מאמתים לפי אורך ולפי אמון במקור, אחרת X-Forwarded-For שהוחדר ידנית היה עוקף את המסנן.
את סדר הכללים הפכנו לטובת רשימת ההיתר: תת-רשתות מהימנות וכתובות שירות של הפרימטר נבדקות לפני החסימות, והחסימות מופרדות לפי מחלקות — פרסרים, סורקי פגיעויות, קצב בקשות חריג.
ליומן נכתבת כעת הכתובת המקורית, שרשרת הפרוקסי ומזהה הלקוח — האירוע מנותח לפי רשומה אחת. הסירובים ללקוחות מהימנים פסקו, שיעור הבקשות עם כתובת נכונה עלה ל-100%, ואיתור האשם ביומנים הצטמצם מ-40 דקות ל-2–3.
כללים חדשים לפני העלאה אנו מריצים על העתק של לוגים מייצור במצב צל — את הרגרסיה רואים לפני שהלקוח רואה אותה.
במה שונה הסינון במאזן העומסים מבדיקה באפליקציה
כלל במאזן העומסים מופעל לפני שהבקשה מגיעה לאפליקציה: החיבור נחסם בכניסה, הערוץ המוצפן אינו עולה, הוורקרים אינם תופסים זיכרון וחיבורים מהמאגר. זוהי חסימה מוקדמת — היא זולה מכל בדיקה בקוד, כיון שהיא מכבה עומס בנקודה העליונה ביותר. הנתונים ברמה זו מועטים: כתובת הלקוח, פורט, שם הצומת, מוני תדירות הפניות.
בדיקה באפליקציה רואה יותר — טוקן, סשן, תפקיד, מזהה שוכר, נתיב וגוף הבקשה. מנגד, היא משלמת את מלוא עלות העיבוד: הבקשה כבר התקבלה, פורקה, הוקם הקשר. מכאן גם סדר הבדיקות: סינון לפי כתובת — בכניסה, ספי תדירות — במאזן העומסים, החלטות לפי זהות — כבר בקוד.
המלכודת העיקרית — שכפול כללים. אם אותה רשימת כתובות קיימת גם בקונפיגורציה של מאזן העומסים וגם במטפל האפליקציה, הן יתפלגו: את העריכה יבצעו במקום אחד, והשני יישאר עם הגרסה הקודמת.
גרוע מכך, הסירוב מגיע ללא הקשר — בלוגים של האפליקציה הבקשה פשוט אינה קיימת, והניתוח מתחיל בשאלה אם היא בכלל הייתה.
בנפרד על הכתובת האמיתית. מאחורי פרוקסי כתובת הלקוח מוחלפת בכתובת המתווך, והכלל מתחיל להכניס או לחסום את הלא נכון. זה מטופל באמון בכותרת X-Forwarded-For רק מצמתי ביניים מוכרים ובפירוק מפורש של השרשרת — אחרת הכתובת מזויפת בכותרת אחת, והמסנן מפסיק להיות בעל משמעות.
ספקות טכניים נפוצים בעת הגדרת גישה
השאלות שנשאלות לפני ההתחלה כמעט תמיד נוגעות לא לתחביר הכללים, אלא להתנהגות המערכת תחת עומס ואחרי שינויים. להלן — תשובות קצרות שמסירות את רוב הספקות לפני תחילת העבודות.
לקוחות מגיעים עם כתובת מוחלפת — המסנן יפעל באופן שגוי?
אם התעבורה עוברת דרך מאזן עומסים או רשת הפצה, בסוקט נראית כתובת המתווך, ולא של הלקוח. את הכתובת האמיתית אנו משחזרים לפי כותרת ההעברה ולפי ההנחיות real_ip_header ו-set_real_ip_from, אחרת הכללים מוחלים על צומת הביניים. בהמשך הרשימות פועלות כבר לפי הכתובת האמיתית.
האם אנו עלולים לחסום לקוחות פעילים?
הסיכון קיים רק במעבר חד למצב «הכל אסור, מלבד הרשימה». לכן תחילה מפעילים תיעוד ללא חסימה, אוספים את התעבורה בפועל ולפיה בונים את רשימת ההיתר. ההשבתה — בשורת קונפיגורציה אחת, ללא הפעלה מחדש של השירות.
אצלנו כבר פרוס פרוקסי — האם התרשים משתנה?
משתנה הצומת שעליו מוחלים הכללים: הוא צריך להיות הראשון שמקבל את החיבור. אם מציבים את המסנן אחרי המתווך, הוא יראה אותה כתובת עבור כולם, או יחסום את כל התעבורה, או לא יחסום דבר.
באיזו תדירות לבחון מחדש את הרשימות?
לפי אירועים — משרד חדש, החלפת ספק אצל שותף, הוצאת שירות משימוש. בנוסף, התאמה מתוכננת אחת לרבעון והתיישנות אוטומטית של רשומות זמניות, כדי שהרשימה לא תהפוך למזבלה של חריגים היסטוריים.
כיצד להבין שהמסנן חוסם גורמים מיותרים?
אנו מנהלים מוני סירובים לכל כלל ומציגים אותם בניטור: עלייה בשיעור הסירובים בנתיב מסוים — אות לבחון מחדש את הרשומה, ולא להמתין לפניות. התראות שווא אנו מנתחים לפי לוגים עם כתובת, נתיב וזמן.
נדון במשימת הסינון שלכם ונחזור עם תוכנית עבודה
כדי שהסינון יעבוד בצורה צפויה, אנו מתחילים מתרשים מעבר התעבורה: היכן נמצא מאזן העומסים, באיזה צומת מסתיימת ההצפנה ובאיזו נקודה הולכת לאיבוד כתובת הלקוח האמיתית.
בתמונה זו רואים מיד אילו כותרות מגיעות ל-nginx ול-Apache, היכן רשימת הכתובות המותרות תפעל באופן שגוי, והיכן רשימת האסורות תשאיר מעקף.
בהמשך אנו קובעים את הרכב שלבי ההטמעה ואת גבולות העבודה. את תוכנית העבודה בנושא הגישות אנו מתאמים לפני עריכות בקונפיגורציה — עם סדר ההעלאה, נקודות החזרה לאחור ואחראים מצדכם.
- תרשים מעבר התעבורה עם נקודות שבהן נקבעת כתובת הלקוח האמיתית.
- כללים ל-nginx ול-Apache עם עדיפויות, חריגים וסדר החלה.
- הגדרת פרוקסים וכותרים מהימנים, כדי שלא ניתן יהיה להחליף את הכתובת האמיתית מבחוץ.
- תקנון עדכון רשימות הגישה וסדר הוספת כתובות חדשות.
- בדיקות בסביבת בדיקות ועל תעבורת פרודקשן, כולל החזרה לאחור של כללים.
- תיעוד הקונפיגורציה ומסירה לצוות התמיכה שלכם.
תארו את משימת הסינון: מה כבר מוגדר, היכן נמצאים הפרוקסים ואילו כתובות יש להכניס או לחסום. נחזור עם הערכת עבודה ותוכנית, שבה לכל שלב מצוינים לוחות זמנים ותוצאה.







