پورت چیست و سرویسها در Linux چگونه گوش میدهند
با مفهوم پورت و تفاوت TCP و UDP آشنا شوید. یاد بگیرید چگونه با دستور ss پورتهای باز را در Linux شناسایی کنید و تفاوت پورتهای عمومی و محلی را درک کنید.
مفهوم واقعی پورت چیست
پورت یک عدد است که به یک سرور اجازه میدهد چندین سرویس را همزمان بدون اختلال در ترافیک آنها اجرا کند. VPS شما یک IP address دارد، اما ممکن است همزمان یک web server، یک SSH server و یک database را اجرا کند. وقتی یک packet وارد میشود، سیستمعامل باید بداند این بسته متعلق به کدام سرویس است. شماره پورت پاسخ این سوال است. ترافیک وب به پورت 443 میرود و SSH به پورت 22. آدرس IP بسته را به سرور شما میرساند؛ پورت آن را به برنامه درست در آن سرور هدایت میکند.
پورت یک عدد 16-bit است: 16 بیت اعداد 0 تا 65535 را پوشش میدهند و عدد 0 رزرو شده است، بنابراین در عمل پورتها از 1 تا 65535 هستند. پورتهای زیر 1024 پورتهای "well-known" هستند و برای باز کردن آنها نیاز به دسترسی root است؛ به همین دلیل سرویسهای استاندارد در آنجا قرار دارند: 22 برای SSH، 80 برای HTTP، 443 برای HTTPS و 53 برای DNS. هر چیزی بالاتر از 1024 برای برنامههای معمولی آزاد است.
دو نوع پورت وجود دارد: TCP و UDP؛ شماره پورت در یکی از آنها با همان شماره در دیگری متفاوت است. TCP یک پروتکل مبتنی بر اتصال (connection-based) است که اکثر سرویسها مانند SSH، HTTP و پایگاههای داده از آن استفاده میکنند. UDP بدون اتصال (connectionless) است و برای مواردی مانند DNS و برخی VPNها استفاده میشود. وقتی یک firewall را تنظیم میکنید، معمولاً باید نوع آن را مشخص کنید، مثلاً 22/tcp.
Listening به معنای منتظر بودن یک برنامه در یک پورت است
برنامهای که میخواهد اتصالات را دریافت کند، از هسته سیستم (kernel) میخواهد که روی یک پورت "listen" کند. از آن لحظه، پورت روی ماشین باز میشود و برنامه به هر چیزی که به آن برسد پاسخ میدهد، مشروط بر اینکه firewall اجازه دهد. پورتی که هیچ برنامهای روی آن listen نمیکند، به سادگی اتصالات را رد میکند. بنابراین اولین سوال در هر بررسی امنیتی این است: چه چیزی در حال listen کردن است و در کجا.
دستور پاسخ به این سوال ss است:
sudo ss -tlnpمعنای flagها عبارتند از: TCP (t)، فقط سوکتهای در حال گوش دادن (l)، پورتهای عددی (n، بنابراین شما 22 را میبینید نه ssh)، و فرآیند مالک (p). یک نتیجه معمولی:
State Recv-Q Local Address:Port Process
LISTEN 0 0.0.0.0:22 sshd
LISTEN 0 127.0.0.1:5432 postgres
LISTEN 0 [::]:80 nginxستون Process به شما میگوید که هر پورت متعلق به کدام برنامه است؛ این روشی است که با آن برنامهای را که نباید باز میماند، پیدا میکنید.
ستون Local Address بخشی است که اهمیت دارد
آدرس مقابل هر پورت را با دقت بخوانید، زیرا این آدرس تعیین میکند چه کسی میتواند به سرویس دسترسی داشته باشد. سه حالت وجود دارد که مدام با آنها روبرو خواهید شد.
0.0.0.0:22 به معنای "listen کردن روی تمام IPv4 addressهایی که این ماشین دارد" است، از جمله آدرس عمومی آن. سرویس در صورت اجازه firewall، از طریق IPv4 از اینترنت قابل دسترسی است.
[::]:80 همان معنا را برای IPv6 دارد: listen کردن روی تمام IPv6 addressها، از جمله آدرس عمومی. بسیاری از برنامهها به صورت پیشفرض در اینجا bind میشوند و در Linux یک سوکت :: اغلب IPv4 را نیز میپذیرد.
127.0.0.1:5432 به معنای "listen کردن فقط روی loopback" است. 127.0.0.1 آدرسی است که یک ماشین برای صحبت با خودش استفاده میکند و از هیچ جای دیگری قابل مسیریابی (routable) نیست. سرویسی که اینجا bind شده باشد، فقط از طریق همان سرور قابل دسترسی است و هرگز از اینترنت قابل دسترسی نیست، فارغ از اینکه firewall شما چه میگوید. خط مربوط به Postgres در بالا، از نظر ساختاری ایمن است.
قاعده کاربردی از این موضوع استخراج میشود: یک database، یک cache، یا یک پنل مدیریت که فقط برنامههای خودتان از آن استفاده میکنند، باید به 127.0.0.1 bind شوند، نه به 0.0.0.0. اگر سرویس هرگز روی یک آدرس عمومی listen نکند، مهاجم چیزی برای دسترسی ندارد.
Listening با قابل دسترس بودن (reachable) متفاوت است
یک تمایز دیگر باعث جلوگیری از سردرگمی زیاد میشود. باز بودن یک پورت در ماشین (به این معنی که یک برنامه در حال listen کردن است) با قابل دسترس بودن آن پورت از بیرون (به این معنی که firewall اجازه میدهد) متفاوت است. برای اینکه یک کلاینت از راه دور بتواند متصل شود، هر دو شرط باید برقرار باشد.
بنابراین دو لایه کنترلی وجود دارد. شما با تنظیم bind address هر سرویس، تعیین میکنید چه چیزی listen کند. و شما با یک firewall، تعیین میکنید دنیای بیرون به چه چیزی دسترسی داشته باشد. یک سرور با مدیریت خوب از هر دو استفاده میکند: سرویسها فقط در جایی که نیاز است bind میشوند و یک firewall هر چیزی را که صراحتاً اجازه ندادهاید، مسدود میکند. خواندن آنچه در حال listen کردن است با استفاده از ss مرحله اول است؛ تصمیمگیری در مورد آنچه firewall اجازه میدهد مرحله دوم است که در firewalls 101 with UFW پوشش داده شده است.
یک نکته ظریف وجود دارد که باعث اشتباه کاربران میشود. IPv4 و IPv6 از هم جدا هستند و یک firewall که فقط IPv4 را پوشش میدهد، سرویسهای [::] را در IPv6 باز میگذارد. این تله خاص، مقاله مخصوص خود را دارد: the IPv6 firewall trap.
FAQ
چگونه ببینم چه پورتهایی در سرور Linux من باز هستند؟
دستور sudo ss -tlnp را برای TCP یا sudo ss -ulnp را برای UDP اجرا کنید. این دستور تمام سوکتهای در حال listen، پورت، آدرس محلی که به آن bind شده و فرآیند مالک آن را لیست میکند. ستون Local Address را بخوانید: 0.0.0.0 یا [::] به این معنی است که سرویس در معرض شبکه قرار دارد، در حالی که 127.0.0.1 به این معنی است که فقط روی خود ماشین listen میکند.
تفاوت 0.0.0.0 و 127.0.0.1 چیست؟
0.0.0.0 به معنای "listen کردن روی تمام IPv4 addressها" است، از جمله آدرس عمومی، بنابراین سرویس از طریق شبکه قابل دسترسی است. 127.0.0.1 همان loopback است، آدرسی که ماشین برای صحبت با خودش استفاده میکند و از هیچ جای دیگری قابل مسیریابی نیست، بنابراین سرویسی که به آن bind شده باشد فقط به صورت محلی قابل دسترسی است. سرویسهای داخلی را به 127.0.0.1 bind کنید تا هرگز در معرض شبکه نباشند.
آیا برای کار کردن یک سرویس نیاز به باز کردن پورت در firewall دارم؟
فقط برای سرویسهایی که باید از ماشینهای دیگر قابل دسترسی باشند. سرویسی که به 127.0.0.1 bind شده باشد نیازی به rule در firewall ندارد زیرا هیچ چیز خارجی نمیتواند به آن دسترسی داشته باشد. سرویسی روی 0.0.0.0 یا [::] به یک rule در firewall برای اجازه دادن به ترافیک نیاز دارد و باید به صورت پیشفرض مسدود باشد تا زمانی که شما یکی اضافه کنید.
تفاوت پورت TCP و پورت UDP چیست؟
TCP مبتنی بر اتصال است و توسط اکثر سرویسها مانند SSH، وبسرورها و پایگاههای داده استفاده میشود. UDP بدون اتصال است و توسط DNS و برخی VPNها استفاده میشود. یک شماره یکسان در TCP و UDP پورتهای مجزایی هستند، بنابراین 53/tcp و 53/udp متفاوت هستند. وقتی قوانین firewall را مینویسید، باید پروتکل را مشخص کنید، مثلاً 22/tcp.