SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-31

UFW ו־IPv6: איך לסגור פורטים פתוחים ב־VPS

כללי UFW וחומת הענן עשויים לסנן רק IPv4, בעוד שירותים חשופים דרך IPv6. גלו איך לזהות את הפער ב־Ubuntu 24.04 ולסגור אותו ב־VPS.

מלכודת חומת האש של IPv6 במשפט אחד

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

במדריך הזה נראה מה מקור הפער הזה ב־VPS רגיל עם Ubuntu 24.04, כיצד לראות בדיוק מה אתם חושפים, וכיצד לסגור את החשיפה. UFW אינו הגורם לבעיה. בהתקנה מודרנית של Ubuntu, UFW כבר מטפל ב־IPv6. החשיפה נובעת מהשכבות שסביבו ומשירותים שלא ידעתם שהם מאזינים.

מדוע ה־VPS שלך משתמש ב־IPv6 מלכתחילה

כמעט כל VPS כיום מגיע עם כתובת IPv6 ציבורית, ולעיתים קרובות עם /64 שלם, לצד כתובת ה־IPv4 שלו. בדקו את הכתובת שלכם:

ip -6 addr show scope global
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    inet6 2001:db8:2a::1/64 scope global

2001:db8:2a::1 הזה ניתן לניתוב מכל מקום באינטרנט, בדיוק כמו כתובת ה־IPv4 שלכם. כעת בדקו אילו שירותים מאזינים:

sudo ss -tlnp
State   Recv-Q  Local Address:Port   Process
LISTEN  0       0.0.0.0:22           sshd
LISTEN  0       [::]:22              sshd
LISTEN  0       127.0.0.1:5432       postgres
LISTEN  0       [::]:8080            docker-proxy

קראו היטב את העמודה Local Address. 0.0.0.0:22 פירושו "האזנה בכל כתובות ה־IPv4". [::]:22 פירושו "האזנה בכל כתובות ה־IPv6". 127.0.0.1:5432 קשור ל־loopback ואינו ציבורי כלל, ולכן השורה של Postgres בטוחה. שתי השורות של [::] מאפשרות לכל האינטרנט לגשת אליהן דרך IPv6, והשורה של docker-proxy היא מסוג הדברים ששוכחים שהפעלתם.

רוב ה־daemons נקשרים ל־:: כברירת מחדל, משום שב־Linux socket מסוג :: מקבל בדרך כלל גם IPv4. לכן ברירת המחדל של שרת חדש היא "להשיב בשני ה־stacks, בכל מקום". ה־firewall שלכם הוא המחסום היחיד מול התעבורה הזו. לכן firewall שבודק רק stack אחד הוא בעיה ממשית.

מהיכן נוצר בפועל הפער ב־IPv6

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

1. חומת אש בענן שמסננת IPv4 בלבד. חומות אש רבות של ספקי ענן ומוצרי security group התפתחו סביב IPv4, ולכן הן מתעלמות מ־IPv6 או דורשות כללי IPv6 נפרדים שיש להוסיף ידנית. אם חומת האש היחידה שלכם היא זו שמוגדרת בלוח הבקרה של הספק, והיא אינה מכסה IPv6, שירותי [::] שלכם חשופים ללא קשר למה שמוגדר לגבי פורט 22 ב־IPv4. קראו את תיעוד חומת האש של הספק וחפשו בו במפורש את המונח IPv6.

2. שימוש ידני ב־iptables ללא ip6tables. הפקודה iptables מטפלת רק בטבלאות IPv4. ל־IPv6 יש פקודה נפרדת לחלוטין, ip6tables, עם מערכת כללים נפרדת משלה. אם כתבתם סקריפט firewall שמכיל שורות רבות של iptables -A INPUT ..., אך לא כתבתם את כללי ip6tables המקבילים, חומת האש של IPv6 ריקה. שרשרת INPUT ריקה, עם מדיניות ברירת מחדל ACCEPT, מאפשרת הכול:

sudo ip6tables -L INPUT -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

זהו המלכוד המלא במסך אחד. IPv4 מסונן, ואילו IPv6 מקבל תעבורה מכל מקור.

3. Docker מפרסם פורטים ישירות, תוך עקיפת חומת האש. כאשר מריצים docker run -p 8080:80, Docker מוסיף כללים משלו לפני הכללים של UFW. לכן אפשר לגשת לפורט שפורסם גם כאשר ufw status מציין שהפורט חסום. בגרסאות מודרניות של Docker הדבר נכון גם עבור IPv6. מדוע Docker עוקף את UFW וכיצד לסנן כראוי פורטים של מכולות מסביר את המנגנון ואת דרכי התיקון. ראו היסודות של Docker Compose ב־VPS כדי להבין כיצד מגדירים את הפורטים האלה.

4. UFW כאשר התמיכה ב־IPv6 כבויה. UFW תומך ב־IPv6, אך רק כאשר מגדירים אותו לכך. בדקו את ההגדרה:

grep IPV6 /etc/default/ufw

בגרסאות מודרניות של Ubuntu מופיע IPV6=yes, ולכן UFW מחיל כל כלל על שתי מחסניות התקשורת. אם מופיע IPV6=no, בעקבות שימוש ב־image ישן או במדריך ישן, כל כלל UFW שכתבתם חל על IPv4 בלבד, ו־IPv6 נשאר ללא ניהול.

בדקו בדיוק מה אתם חושפים

אל תנחשו. מדדו זאת מבחוץ. תחילה הציגו את ה־listeners וציינו כל listener שמאזין ב־:::

sudo ss -tlnp | grep '::'

לאחר מכן, ממחשב אחר, התחברו לכתובת ה־IPv6 הציבורית של השרת ונסו פורט שלדעתכם סגור:

curl -6 -v http://[2001:db8:2a::1]:8080/

אם מתקבלים דף או banner, הפורט פתוח ב־IPv6. פורט סגור מחזיר Connection refused או גורם ל־timeout. שני הכשלים האלה אינם אותו סימן. ההבדל בין חיבור שנדחה לבין timeout מראה אם ה־host השיב ודחה אתכם, או ש־firewall השמיט את החבילה בלי להשיב. לקבלת תמונה מלאה, סרקו את כתובת ה־IPv6 באמצעות nmap מחוץ לשרת:

nmap -6 2001:db8:2a::1

כל פורט ש־nmap מדווח עליו כפתוח ב־IPv6 הוא פורט שכל האינטרנט יכול להגיע אליו, בלי קשר לתוצאות סריקת ה־IPv4. השוואה בין סריקות ה־IPv4 וה־IPv6 זו לצד זו היא הדרך המהירה ביותר למצוא את הפער: כל דבר שפתוח ב־-6 אך סגור ב־IPv4 הוא שירות שה־firewall שלכם אינו מגן עליו.

סגרו את הפער

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

sudo sed -i 's/^IPV6=no/IPV6=yes/' /etc/default/ufw
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose

אם UFW כבר היה פעיל כאשר שיניתם את IPV6=yes, השינוי ייכנס לתוקף רק לאחר הפעלת sudo ufw reload.

ufw status מציג כל כלל פעמיים: פעם אחת ללא סיומת, ופעם אחת עם הסיומת (v6). כאשר מופיעות שורות (v6), המשמעות היא ש־UFW מסנן גם תעבורת IPv6:

22/tcp                     ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)

אם אתם מנהלים את iptables ידנית, שכפלו כל כלל גם ב־ip6tables, או עברו ל־nftables, שטבלאות inet שלו מכסות את IPv4 ואת IPv6 במקום אחד ומונעות את כל סוג הטעות הזה. טבלת סינון יחידה של nftables מסוג inet היא הפתרון הנקי ביותר כאשר אתם כותבים את הכללים בעצמכם. אם ה־VPS שלכם מריץ Rocky או AlmaLinux במקום Ubuntu, אין UFW להגדרה, ובמקום זאת מנהלים את firewalld כממשק הקדמי, והוא מחיל את כללי האזורים שלו על שתי מחסניות הפרוטוקולים בבת אחת.

קשרו שירותים שאינכם רוצים לחשוף לציבור ל־loopback. מסד נתונים, לוח ניהול או נקודת קצה של מדדים כמעט אף פעם אינם זקוקים לכתובת ציבורית. קשרו אותם ל־127.0.0.1 ול־::1, כדי שלא יאזינו מלכתחילה לכתובת הניתנת לניתוב. עבור Postgres, הגדירו את listen_addresses = 'localhost'. עבור שרת יישומים, קשרו אותו ל־127.0.0.1 והציבו לפניו reverse proxy. סגירת ה־listener עדיפה על חסימתו באמצעות firewall, משום שבמצב כזה אין שירות שניתן להגיע אליו.

אל תסמכו על UFW שיגן על הפורטים ש־Docker מפרסם. פרסמו את פורטי המכולות לכתובת מסוימת במקום לכל ממשק, לדוגמה -p 127.0.0.1:8080:80, כך שניתן יהיה לגשת לפורט רק מהמארח ומכל רכיב שאליו אתם מנתבים במכוון. כאשר מכולה חייבת להיות ציבורית, הציבו אותה מאחורי reverse proxy של Traefik ופרסמו רק את ה־proxy, ולא כל יישום בנפרד.

הוסיפו כללי IPv6 ל־firewall של הספק, או קבלו שהוא אינו משמש כ־firewall שלכם עבור IPv6, ותנו ל־UFW או ל־nftables במארח לבצע את המשימה במקום זאת.

ודאו שהפורט אכן סגור

הריצו שוב את אותה בדיקה חיצונית לאחר השינויים:

curl -6 -v http://[2001:db8:2a::1]:8080/
nmap -6 2001:db8:2a::1

הפורט שנענה קודם לכן אמור כעת לדחות את החיבור או לגרום ל־timeout, ו־nmap אמור לדווח שהוא מסונן או סגור. אם פורט עדיין פתוח, עברו שוב על ארבעת המקורות שלמעלה: שירות שעדיין מאזין ב־:: בלי כלל לפניו, כלל של Docker שנמצא לפני UFW, או firewall של ספק שמעולם לא טיפל בתעבורת IPv6.

עדיף אף יותר למנוע לחלוטין גישה של שירותים רגישים מהאינטרנט הציבורי. הציבו את SSH ואת לוחות הניהול מאחורי VPN של WireGuard וחסמו את הפורטים שלהם באמצעות firewall, כך שיענו רק דרך המנהרה. במקרה כזה שאלת החשיפה ב־IPv6 אינה חלה עליהם. כדי להאט סריקות brute-force שפוגעות בכל מה שנשאר ציבורי, הוסיפו Fail2ban לפני SSH על גבי firewall עם מדיניות ברירת מחדל של דחיית כל התעבורה.

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

FAQ

האם UFW חוסם IPv6 כברירת מחדל?

בהתקנה מודרנית של Ubuntu 24.04, כן. UFW קורא את IPV6=yes מתוך /etc/default/ufw ומחיל כל כלל גם על IPv4 וגם על IPv6, ו־ufw status מציג את כללי IPv6 עם הסיומת (v6). הבעיה מתעוררת כאשר IPV6=no (מתמונה ישנה או ממדריך ישן), כאשר מסתמכים על firewall של ספק שמסנן IPv4 בלבד, או כאשר Docker מפרסם פורט ועוקף את UFW. בדקו את המתג באמצעות grep IPV6 /etc/default/ufw.

כיצד לבדוק מה ה־VPS שלי חושף ב־IPv6?

הריצו sudo ss -tlnp וציינו כל מאזין שהכתובת המקומית שלו מתחילה ב־[::]. המשמעות היא שהוא עונה בכל ממשק IPv6. לאחר מכן, ממחשב אחר, בדקו ישירות את כתובת ה־IPv6 הציבורית של השרת באמצעות curl -6 -v http://[YOUR:IPV6::ADDR]:PORT/, או סרקו אותה באמצעות nmap -6 YOUR:IPV6::ADDR. כל פורט שפתוח בסריקת IPv6 אך סגור ב־IPv4 מצביע על פער בתצורה.

מדוע אני יכול להגיע לפורט של מכולת Docker שלי כאשר UFW מציין שהוא חסום?

Docker מוסיף את כללי ה־firewall שלו לפני הכללים של UFW כאשר מפרסמים פורט באמצעות -p. לכן אפשר להגיע לפורט שפורסם, אף ש־ufw status מציג אותו כחסום. הדבר קורה ב־IPv4, וגם ב־IPv6 כאשר תמיכת ה־IPv6 של Docker מופעלת. פרסמו את הפורט לכתובת מסוימת, כגון -p 127.0.0.1:8080:80, או הציבו את המכולה מאחורי reverse proxy ופרסמו רק את ה־proxy.

האם עדיין דרוש לי firewall ל־IPv6 אם ה־firewall של IPv4 מוגדר היטב?

כן. IPv4 ו־IPv6 הם מחסניות רשת נפרדות, עם כללי firewall נפרדים. קבוצה מושלמת של כללי IPv4 אינה משפיעה כלל על תעבורת IPv6. אם ל־VPS שלכם יש כתובת IPv6 ציבורית, וכמעט לכל ה־VPS יש כתובת כזו, כל שירות שמאזין ב־:: יישאר נגיש דרך IPv6 עד שכלל firewall של IPv6 או קישור ל־loopback יפסיקו זאת.

כיצד לגרום לשירות להאזין רק ב־IPv4, או רק ב־localhost?

הגדירו את כתובת הקישור של השירות בקובץ התצורה שלו. קשרו ל־127.0.0.1 כדי לאפשר loopback של IPv4 בלבד, או ל־0.0.0.0 כדי להאזין בכל כתובות ה־IPv4 בלי מאזין IPv6. Postgres משתמש ב־listen_addresses, ‏SSH משתמש ב־ListenAddress, ורוב שרתי היישומים מספקים דגל host או bind. אשרו את התוצאה באמצעות sudo ss -tlnp ובדקו שה־Local Address אינו מציג עוד את [::].