SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor

پورت چیست و سرویس‌های Linux چگونه گوش می‌دهند؟

پورت ترافیک ورودی را به سرویس درست می‌رساند. با دستور ss سرویس‌های در حال گوش‌دادن را بخوانید و پورت محلی را از پورت عمومی تشخیص دهید؛ همراه با مثال‌های 22 و 443.

پورت دقیقاً چیست

پورت عددی است که به یک سرور اجازه می‌دهد چندین سرویس را هم‌زمان اجرا کند، بدون آنکه ترافیک آن‌ها با هم تداخل پیدا کند. سرور مجازی (VPS) شما یک آدرس IP دارد، اما ممکن است هم‌زمان یک وب‌سرور، یک سرور SSH و یک دیتابیس را اجرا کند. وقتی بسته‌ای (packet) می‌رسد، سیستم‌عامل باید بداند این بسته برای کدام‌یک از آن‌هاست. شماره پورت پاسخ این پرسش است. ترافیک HTTPS معمولاً به پورت 443 و SSH به پورت 22 می‌رود. آدرس IP بسته را به سرور شما می‌رساند؛ پورت آن را به برنامه صحیح روی همان سرور هدایت می‌کند.

پورت یک عدد 16 بیتی است: 16 بیت بازه‌ای از 0 تا 65535 ایجاد می‌کند و چون 0 رزرو شده است، پورت‌ها در عمل از 1 تا 65535 هستند. پورت‌های زیر 1024 پورت‌های «شناخته‌شده» (well-known) هستند و به‌طور پیش‌فرض، لینوکس فقط به root (یا برنامه‌ای که قابلیت CAP_NET_BIND_SERVICE به آن داده شده) اجازه می‌دهد آن‌ها را باز کند؛ به همین دلیل سرویس‌های استاندارد در آنجا قرار دارند: 22 برای SSH، 80 برای HTTP، 443 برای HTTPS و 53 برای DNS. پارامتر net.ipv4.ip_unprivileged_port_start در sysctl می‌تواند این مرز را تغییر دهد، اما مقدار پیش‌فرض آن 1024 است. هر عددی از 1024 به بالا برای برنامه‌های معمولی قابل استفاده است.

دو نوع پورت وجود دارد: TCP و UDP، و شماره پورت در یکی از دیگری مجزا است. TCP پروتکل مبتنی بر اتصال است که اکثر سرویس‌ها مانند SSH، HTTP و دیتابیس‌ها از آن استفاده می‌کنند. UDP بدون اتصال است و برای مواردی مانند DNS و برخی VPNها استفاده می‌شود. هنگام باز کردن فایروال، معمولاً نوع آن را مشخص می‌کنید، برای مثال 22/tcp.

گوش دادن (Listening) به این معناست که یک برنامه منتظر اتصال روی یک پورت است

برنامه‌ای که قصد دریافت اتصالات را دارد، از هسته سیستم‌عامل (kernel) می‌خواهد که روی یک پورت «گوش دهد» (listen). از آن لحظه، پورت روی ماشین باز می‌شود و برنامه به هر چیزی که به آنجا برسد پاسخ می‌دهد؛ البته این موضوع تابع تنظیمات فایروال نیز هست. پورتی که هیچ برنامه‌ای روی آن گوش نمی‌دهد، اتصالات را مستقیماً رد می‌کند. بنابراین، اولین پرسش در هر بررسی امنیتی این است: چه چیزی و در کجا در حال گوش دادن است.

دستور پاسخ به این پرسش ss است:

sudo ss -tlnp

فلگ‌های این دستور به معنای پروتکل TCP (t)، فقط سوکت‌های در حال گوش دادن (l)، پورت‌های عددی (n، تا به جای ssh، مقدار 22 را ببینید) و پروسه مالک (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 یعنی «روی تمام آدرس‌های IPv4 این ماشین گوش بده»، که شامل آدرس عمومی آن نیز می‌شود. این سرویس از طریق اینترنت و با پروتکل IPv4 قابل دسترسی است (اگر فایروال اجازه دهد).

[::]:80 همین معنا را برای IPv6 دارد: گوش دادن روی تمام آدرس‌های IPv6، از جمله آدرس‌های عمومی. بسیاری از برنامه‌ها به‌طور پیش‌فرض اینجا bind می‌شوند و در لینوکس، یک سوکت :: اغلب IPv4 را نیز می‌پذیرد.

127.0.0.1:5432 یعنی «فقط روی loopback گوش بده». 127.0.0.1 آدرسی است که ماشین برای صحبت با خودش استفاده می‌کند و تحت تنظیمات پیش‌فرض هسته، از هیچ جای دیگری قابل مسیریابی نیست. سرویسی که اینجا bind شده، فقط از داخل همان سرور قابل دسترسی است، نه از اینترنت، حتی اگر فایروال شما پورت را باز گذاشته باشد. آن خط مربوط به Postgres در بالا به‌طور پیش‌فرض امن است. استثنا، تنظیماتی در هسته به نام route_localnet است: این گزینه به‌طور پیش‌فرض خاموش است، اما برخی ابزارها آن را روشن می‌کنند (مانند kube-proxy در Kubernetes) و با وجود آن، به همراه قوانین مسیریابی یا NAT مناسب، ترافیک loopback می‌تواند از بیرون برسد. sysctl -a | grep route_localnet باید در هر خط = 0 را نشان دهد.

قانون عملی از اینجا به دست می‌آید: دیتابیس، کش یا پنل مدیریتی که فقط برنامه‌های خودتان از آن استفاده می‌کنند، باید روی 127.0.0.1 باشد، نه 0.0.0.0. اگر سرویسی هرگز روی آدرس عمومی گوش ندهد، چیزی برای دسترسی مهاجم وجود نخواهد داشت.

گوش دادن به معنای قابل دسترسی بودن نیست

یک تفاوت دیگر، سردرگمی زیادی را برطرف می‌کند. باز بودن یک پورت روی ماشین، به این معنی که برنامه‌ای در حال گوش دادن است، با قابل دسترسی بودن آن پورت از بیرون (یعنی فایروال اجازه عبور می‌دهد) متفاوت است. برای اتصال یک کلاینت از راه دور، هر دو باید برقرار باشند. این دو نوع خطا از سمت کلاینت هم متفاوت به نظر می‌رسند: اتصالی که رد (refused) می‌شود معمولاً یعنی چیزی در حال گوش دادن نبوده است، در حالی که اتصالی که معلق می‌ماند و سپس زمان آن تمام می‌شود (times out)، معمولاً یعنی فایروال بسته را مسدود کرده است؛ این دقیقاً همان چیزی است که آن دو خطای SSH به شما می‌گویند.

بنابراین دو لایه کنترل وجود دارد. شما با تنظیم آدرس bind هر سرویس، تصمیم می‌گیرید چه چیزی گوش دهد. و با یک فایروال، تصمیم می‌گیرید دنیای بیرون به چه چیزی دسترسی داشته باشد. یک سرورِ به‌خوبی مدیریت‌شده از هر دو استفاده می‌کند: سرویس‌ها فقط در جایی که نیاز است bind می‌شوند و فایروال هر چیزی را که صراحتاً اجازه نداده‌اید، مسدود می‌کند. خواندن وضعیت گوش دادن با ss گام اول است؛ تصمیم‌گیری درباره آنچه فایروال اجازه می‌دهد گام دوم است که در آموزش فایروال با UFW پوشش داده شده است.

نکته ظریفی وجود دارد که کاربران را به دردسر می‌اندازد. IPv4 و IPv6 از هم جدا هستند و فایروالی که فقط IPv4 را پوشش می‌دهد، سرویس‌های [::] را روی IPv6 باز می‌گذارد. این تله خاص، مطلب مخصوص به خود را دارد: تله فایروال IPv6.

FAQ

چگونه بفهمم چه پورت‌هایی روی سرور لینوکسی من باز است؟

برای TCP دستور sudo ss -tlnp و برای UDP دستور sudo ss -ulnp را اجرا کنید. این دستورات تمام سوکت‌های در حال گوش دادن، پورت، آدرس محلی که به آن bind شده‌اند و فرآیندی که مالک آن‌هاست را لیست می‌کنند. ستون Local Address را بخوانید: 0.0.0.0 یا [::] یعنی سرویس در معرض شبکه قرار دارد، در حالی که 127.0.0.1 یعنی فقط روی خود ماشین گوش می‌دهد.

تفاوت بین 0.0.0.0 و 127.0.0.1 چیست؟

0.0.0.0 یعنی «روی تمام آدرس‌های IPv4 گوش بده»، شامل آدرس عمومی، بنابراین سرویس از شبکه قابل دسترسی است. 127.0.0.1 آدرس loopback است، آدرسی که ماشین برای صحبت با خودش استفاده می‌کند و با تنظیمات پیش‌فرض هسته، از جای دیگری قابل مسیریابی نیست، بنابراین سرویسی که به آن bind شده فقط به‌صورت محلی قابل دسترسی است. سرویس‌های داخلی را روی 127.0.0.1 bind کنید تا از شبکه دور بمانند.

آیا برای کار کردن یک سرویس، باید پورت آن را در فایروال باز کنم؟

فقط برای سرویس‌هایی که باید از ماشین‌های دیگر به آن‌ها دسترسی داشت. سرویسی که روی 127.0.0.1 bind شده، نیازی به قانون اجازه (allow) ندارد، زیرا با تنظیمات پیش‌فرض هسته، هیچ عامل خارجی نمی‌تواند به آن دسترسی پیدا کند. سرویسی که روی 0.0.0.0 یا [::] است، زمانی که فایروال شما به‌طور پیش‌فرض ترافیک ورودی را مسدود می‌کند (که باید همین‌طور باشد)، نیاز به قانون اجازه دارد. اگر فایروالی فعال نیست یا سیاست آن پذیرش همه چیز است، آن سرویس بدون هیچ قانونی از قبل قابل دسترسی است.

تفاوت بین پورت TCP و پورت UDP چیست؟

TCP مبتنی بر اتصال است و توسط اکثر سرویس‌ها مانند SSH، وب‌سرورها و دیتابیس‌ها استفاده می‌شود. UDP بدون اتصال است و توسط DNS و برخی VPNها استفاده می‌شود. شماره یکسان در TCP و UDP پورت‌های متفاوتی هستند، بنابراین 53/tcp و 53/udp با هم فرق دارند. هنگام نوشتن قوانین فایروال، پروتکل را مشخص می‌کنید، برای مثال 22/tcp.