WEBA

הטלאי הזמני של AOL פורש אחרי 20 מיליון התקנות

ג'ייק א. סמית' הכריז על סיום התחזוקה של http_build_url, והסביר למה מסוכן להעביר ספריות קוד פתוח ותיקות לידיים זרות.

631 מילים24 עובדות אומתו

אין פתרון קבוע יותר ממעקף זמני שפשוט עובד. ב־15 בספטמבר 2026 הודיע המהנדס ג'ייק א. סמית' בבלוג שלו על סיום התחזוקה של החבילה jakeasmith/http_build_url ב־Packagist. מה שהתחיל ב־2014 כטלאי מהיר עבור מערכת הניהול הישנה של חברת AOL, הפך במרוצת השנים לתשתית שקטה שמחזיקה רשת עולמית של אתרים. אם אתם מתחזקים שרתי לינוקס או אתרי לקוחות, זה הזמן לבדוק מה באמת יושב לכם בתיקיית ה־vendor.

שום דבר לא נשבר מחר

פרודקשן לא ייפול הלילה. סימון החבילה כנטושה ב־Composer לא מוחק את הקבצים, והגרסאות שכבר שוחררו יישארו זמינות להורדה בשרתי Packagist. הקוד הזה נהנה מתפוצה רחבה: כמעט 20 מיליון התקנות מצטברות, וקצב שוטף של מעל 400 אלף הורדות מדי חודש. הוא מופץ ישירות בתוך מאגרי החבילות של הפצות לינוקס כמו Debian ו־Ubuntu, ומשולב עמוק בתוך מערכות תוכן ותיקות.

לא הייתי ממהר להיכנס לפאניקה.

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

הבאג שגונב אותיות

החבילה כולה מכילה בסך הכל 174 שורות קוד שנכתבו לפני שתים־עשרה שנה. המטרה אז הייתה פשוטה: שדרוג ה־CMS של AOL מגרסת PHP 5.2 לגרסת PHP 5.3 גרר הסרה של הרחבת pecl_http. אותה הרחבה סיפקה את הפונקציה המקורית http_build_url. במקום לשכתב עשרות קריאות קוד במערכת הענקית, סמית' כתב מימוש חלופי שהגדיר את הפונקציה רק במידה והיא חסרה במנוע. המערכת המשיכה לרוץ כרגיל, וסמית' העלה את הפתרון כקוד פתוח מתוך מחשבה שהוא יחזיק שנה או שנתיים.

כתבתי את הקוד הזה כדי להקל על מיגרציה כואבת, עבור עצמי ועבור כל מי שעבר את אותו תהליך.ג'ייק א. סמית' בבלוג האישי

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

סכנת שרשרת האספקה

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

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

מסלול השדרוג לפי גרסה

מי שכותב קוד חדש כבר לא זקוק לפוליפילים מתקופת PHP 5. הפתרון הנקי ביותר שמור למי שמשדרג לגרסאות עדכניות: PHP 8.5 כוללת ממשק רשמי מובנה לטיפול בכתובות תחת Uri\Rfc3986\Uri. המחלקה הזו מאפשרת לפרק, לערוך ולחבר נתיבים בצורה תקנית ומהירה היישר מתוך ליבת השפה, בלי ספריות חיצוניות ובלי קומבינציות מחרוזות מסוכנות.

בשרתים שעדיין מריצים גרסאות ישנות יותר, המסלול הנכון הוא מעבר לספריות קהילתיות מבוססות תקן כמו league/uri, או שילוב ישיר בין הפונקציות המובנות parse_url ו־http_build_query. אין סיבה להשאיר תלות בחבילה שלא תראה עדכונים נוספים, בוודאי בפרויקטים שעוברים תחזוקה שוטפת.

חלופות מומלצות להחלפת http_build_url לפי סביבת הריצה
גרסת PHPפתרון מומלץהשלכות ושיקולים
PHP 8.5 ומעלהUri\Rfc3986\Uriממשק מובנה בליבת השפה, תאימות מלאה לתקן RFC 3986 וללא תלויות חיצוניות.
גרסאות ישנות יותר מ־PHP 8.5ספריית league/uriפתרון קהילתי מתוקנן ומתוחזק, זמין כספרייה עצמאית.
גרסאות ישנות יותר מ־PHP 8.5parse_url ו־http_build_queryשימוש בפונקציות ליבה קיימות ללא התקנת חבילות, מצריך כתיבת פונקציית מעטפת עצמאית.

הקוד הישן עשה את שלו.

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

מה לעשות עכשיובדקו אם החבילה מוגדרת ישירות ב-composer.json שלכם, והחליפו אותה בממשק הליבה של PHP 8.5 או בספריית league/uri.

מקורות

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

מה שואלים על זה

האם אתר וורדפרס שמריץ WPML יפסיק לעבוד בעקבות ההודעה?

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

מדוע המחבר בחר לנטוש את החבילה במקום להעביר את השרביט למתנדב מהקהילה?

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

מהו באג האותיות הידוע שנשאר ללא תיקון בספרייה?

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

באיזה אופן ניתן להחליף את הפונקציה בשרתים שמריצים גרסאות ישנות מ-PHP 8.5?

ניתן להשתמש בספרייה הוותיקה league/uri מבית PHP League, או לבנות מעטפת פשוטה בקוד המשלבת בין הפונקציות המובנות parse_url ו־http_build_query.