برای اتصال SSH به سرورهای Homelab خودم، به روشی تمیزتر نیاز داشتم؛ روشی که هیچ‌کدام از سرویس‌های داخلی را مستقیماً در معرض اینترنت قرار ندهد. راه‌حل، استفاده از یک سرور کوچک Linux SSH Jump بود. این سرور می‌توانست در لبه شبکه قرار بگیرد و تنها یک نقطه ورود کنترل‌شده در اختیارم بگذارد، درحالی‌که سایر سرویس‌ها پشت فایروال شبکه پنهان می‌ماندند.

تنها مشکل این بود که اصلاً دوست ندارم سرورهای قابل‌دسترسی از اینترنت را با پورت‌های آسیب‌پذیر مستقر کنم؛ چون این کار تقریباً مثل این است که یک تابلوی بزرگ «هدف مناسب برای حمله» روی آدرس IP خانه‌تان نصب کنید.

کمتر از نیم‌ساعت بعد از اینکه سرور را آنلاین کردم، لاگ‌ها از تلاش‌های ورود از IPهای تصادفی پر شده بودند. ماجرا فقط یکی دو تلاش کنجکاوانه نبود؛ صدها تلاش به سروری انجام شده بود که حتی یک ساعت هم از راه‌اندازی آن نمی‌گذشت.

بنابراین، سه تغییر نسبتاً ساده انجام دادم که حجم زیادی از این سر و صدا را متوقف کردند و یک هدف SSH که با رمز عبور قابل‌دسترسی بود را به سیستمی بسیار امن‌تر تبدیل کردند. در ادامه با دستورات و تنظیماتی که برای مقابله با ربات‌ها در فضای اینترنت و سرور کاربرد دارد، آشنا می‌شویم.

بات‌ها قبل از اینکه ساخت Jump Box را تمام کنم، آن را پیدا کردند

پورت 22 سرور من را به یک هدف جذاب برای بات‌ها تبدیل کرده بود

این سرور جدید فقط یک وظیفه داشت. قرار بود به‌عنوان یک نقطه ورود کنترل‌شده برای اتصال SSH به زیرساخت Homelab من عمل کند، نه اینکه به یک مسیر حمله عمومی دیگر برای بات‌ها تبدیل شود.

قرار نبود هیچ داشبورد، وب‌سرور یا فایل‌شیرینگی پشت صفحه ورود آن قرار داشته باشد. این فقط یک سرور SSH ساده بود که در لبه شبکه من قرار داشت.

قبل از اینکه سرور را ایمن کنم، می‌خواستم ببینم دقیقاً چه سرویس‌هایی در حال گوش‌دادن هستند. دستور زیر آخرین فعالیت‌های مربوط به SSH را به من نشان داد:

sudo ss -tulpn

نتیجه همان چیزی بود که انتظار داشتم. SSH روی پورت 22 درحال گوش‌دادن بود و سرویس دیگری وجود نداشت.

چگونه یک سرور SSH را در برابر حملات ربات‌های اینترنتی ایمن کنیم؟

در این مرحله، سرور فقط حدود یک ساعت آنلاین بود. بنابراین می‌خواستم تلاش‌های ناموفق اخیر برای اسکن پورت و احراز هویت SSH را بررسی کنم:

sudo journalctl -u ssh --since "1 hour ago" | grep -Ei "failed|invalid|disconnect|authentication"

تعداد تلاش‌ها همین حالا به صدها مورد رسیده بود و نام‌های کاربری امتحان‌شده هم همان حدس‌های تکراری و ساده‌ای مثل root و admin بودند.

بااین‌حال، چند تلاش جالب‌تر هم وجود داشت که در آن‌ها نام‌هایی مثل vagrant، ansible، minecraft و jenkins امتحان شده بود. برای اینکه پرتکرارترین نام‌های کاربری را پیدا کنم، از این دستور استفاده کردم:

sudo journalctl -u ssh --since "1 hour ago" | grep -Eio "invalid user [^ ]+" | sort | uniq -c | sort -nr | head

IPهای مبدأ نیز بسیار متنوع بودند و همه تلاش‌ها از یک آدرس انجام نمی‌شدند:

sudo journalctl -u ssh --since "1 hour ago" | grep -Eio "from ([0-9]{1,3}.){3}[0-9]{1,3}" | awk '{print $2}' | sort | uniq -c | sort -nr | head

خروجی نشان می‌داد که این یک حمله هدفمند نیست. درواقع، با همان ترافیک معمول بات‌ها مواجه بودم که تقریباً بلافاصله پس از قرارگرفتن یک سرور SSH لینوکسی در اینترنت عمومی شروع می‌شود.

انتقال SSH از پورت 22 باعث شد سرور کمتر در معرض دید باشد

این کار SSH را امن نکرد، اما بیشتر ترافیک مزاحم بات‌ها را متوقف کرد

تغییر پورت SSH معمولاً اولین مرحله امن‌سازی لینوکس است که برای هر سرور لینوکسی متصل به اینترنت انجام می‌دهم. البته تصور نمی‌کنم صرفاً تغییر پورت از 22 به این معنی باشد که سرور ناگهان کاملاً امن شده است. اگر کسی واقعاً مصمم باشد یک پورت SSH باز را پیدا کند، تغییر پورت نمی‌تواند جلوی او را بگیرد.

بااین‌حال، این کار می‌تواند حجم لاگ‌های ایجادشده توسط اسکن خودکار بات‌ها را به‌شکل محسوسی کاهش دهد؛ چون سرور دیگر مثل یک هدف آماده و واضح به‌نظر نمی‌رسد.

چگونه یک سرور SSH را در برابر حملات ربات‌های اینترنتی ایمن کنیم؟

بیشتر اسکن‌های بی‌هدف که به سرور من می‌رسیدند، چندان هوشمند نبودند. این‌ها فقط ترافیک خودکاری بودند که به‌دنبال پورت پیش‌فرض SSH می‌گشتند و بارها همان نام‌های کاربری قدیمی را امتحان می‌کردند.

به‌جای اینکه فایل تنظیمات اصلی SSH را مستقیماً ویرایش کنم، یک فایل تنظیمات جداگانه برای SSH ساختم:

sudo nano /etc/ssh/sshd_config.d/99-homeops-hardening.conf

اولین و مهم‌ترین تنظیم هم بسیار ساده بود:

Port 52522

قبل از بارگذاری مجدد SSH، پورت جدید را در فایروال UFW اوبونتو باز کردم. هدف این بود که بعد از فعال‌شدن تنظیمات جدید، به‌اشتباه دسترسی خودم به SSH را قطع نکنم.

سپس از یک ترمینال دیگر، ورود به پورت جدید را امتحان کردم:

ssh -p 52522 home-ops-relay@ggcontentlabs.com

فقط بعد از اینکه مطمئن شدم ورود از طریق پورت جدید بدون مشکل انجام می‌شود، قانون قدیمی فایروال برای پورت 22 را حذف کردم:

sudo ufw delete allow OpenSSH

تغییر پورت را می‌توان تا حدی شبیه این دانست که زنگ در خانه را از کنار خیابان به نقطه‌ای بسیار دورتر منتقل کنید، نه اینکه به‌صورت جادویی SSH را نامرئی کنید.

این کار در برابر حملات Brute Force محافظت ایجاد نمی‌کند؛ آن بخش در مرحله بعدی انجام می‌شود. اما باعث می‌شود بخش زیادی از ترافیک خودکار بات‌ها همان ابتدا متوقف شود.

در اوبونتو، اگر پورت SSH را درحالی‌که از طریق یک نشست SSH فعال به سرور متصل هستید تغییر می‌دهید، باید پس از اطمینان از درست‌کارکردن پورت جدید، Listener مربوط به ssh.socket را نیز غیرفعال کنید.

ورود فقط با کلید SSH، حدس‌زدن رمز عبور را بی‌اهمیت کرد

بات‌ها هنوز می‌توانستند در بزنند، اما دیگر قفلی برای امتحان‌کردن نداشتند

انتقال SSH از پورت پیش‌فرض باعث شد لاگ‌ها تقریباً بلافاصله خلوت‌تر شوند، اما این تغییر بعدی بود که امنیت سرور را واقعاً بیشتر کرد.

بیشتر اسکن‌های خودکار بات‌ها تلاش می‌کردند نام‌های کاربری و رمزهای عبور مختلف را بارها و بارها امتحان کنند؛ شاید به این امید که من آن‌قدر بی‌احتیاط باشم که برای رمز عبور root از یک کلمه رایج استفاده کرده باشم.

ساختن یک رمز عبور پیچیده با استفاده از ابزارهای تولید Passphrase برای حساب root قطعاً یکی از اصول خوب امنیتی است، اما راه‌حل واقعی برای مقابله با حدس‌زدن رمز عبور این است که ورود خودم را به احراز هویت با کلید SSH منتقل کنم.

در این روش، به‌جای اینکه هویت خودم را با رمز عبور ثابت کنم، لپ‌تاپم از یک کلید خصوصی استفاده می‌کند که با کلید عمومی ذخیره‌شده روی سرور مطابقت دارد.

بعد از اینکه مطمئن شدم ورود با کلید SSH به‌درستی کار می‌کند، تنظیمات زیر را به همان فایل امن‌سازی SSH که در مرحله قبل ساختم اضافه کردم:

sudo nano /etc/ssh/sshd_config.d/99-homeops-hardening.conf

سپس این تنظیمات را اضافه کردم:

PasswordAuthentication no

KbdInteractiveAuthentication no

PermitRootLogin no

قبل از بارگذاری مجدد تنظیمات SSH نیز صحت فایل پیکربندی را بررسی کردم:

sudo sshd -t sudo systemctl reload ssh

از اینجا به بعد، بات‌ها می‌توانستند تمام روز رمز عبور حدس بزنند، اما دیگر راهی برای ورود با رمز عبور نداشتند.

همچنین ورود مستقیم حساب root را غیرفعال کردم، اما فقط بعد از اینکه یک حساب کاربری جدید ساختم و دسترسی sudo را به آن دادم:

sudo adduser home-ops-relay-admin

sudo usermod -aG sudo home-ops-relay-admin

سپس کلید SSH را برای این حساب منتقل کردم:

sudo mkdir -p /home/home-ops-relay-admin/.ssh sudo cp ~/.ssh/authorized_keys /home/home-ops-relay-admin/.ssh/authorized_keys sudo chown -R home-ops-relay-admin:home-ops-relay-admin /home/home-ops-relay-admin/.ssh sudo chmod 700 /home/home-ops-relay-admin/.ssh sudo chmod 600 /home/home-ops-relay-admin/.ssh/authorized_keys

درنهایت، برای آزمایش تنظیمات، یک تلاش برای اتصال SSH فقط با رمز عبور و بدون استفاده از کلید عمومی انجام دادم:

ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no -p 52522 home-ops-relay@ggcontentlabs.com

این تلاش ناموفق بود؛ دقیقاً همان چیزی که می‌خواستم ببینم.

لاگ‌ها همچنان تلاش‌های اتصال را نشان می‌دادند، اما دیگر این تلاش‌ها اهمیت چندانی نداشتند.

Fail2ban جلوی بات‌هایی را گرفت که دست‌بردار نبودند

Jump Box بالاخره شروع کرد به بیرون‌کردن مزاحم‌ها

بعد از انتقال SSH از پورت 22 و استفاده از ورود فقط با کلید، سرور دیگر به‌اندازه قبل برای بات‌ها جذاب نبود و حجم ترافیک مزاحم نیز بسیار کمتر شده بود. اما هنوز به یک لایه امنیتی دیگر نیاز داشتم تا بات‌هایی را که همچنان به تلاش‌های خود ادامه می‌دادند، مسدود کند.

Fail2ban ابزار موردعلاقه من در لینوکس برای انجام همین کار است. وقتی یک IP در یک بازه زمانی مشخص، تعداد زیادی تلاش ناموفق داشته باشد، Fail2ban آن IP را برای مدتی در سطح فایروال مسدود می‌کند.

چگونه یک سرور SSH را در برابر حملات ربات‌های اینترنتی ایمن کنیم؟

برای یک Jump Box که مستقیماً به اینترنت عمومی متصل است، Fail2ban یکی از بهترین لایه‌های حفاظتی است که می‌توانم برای افزایش امنیت آن نصب کنم.

راه‌اندازی و پیکربندی Fail2ban حتی پس از تغییر پورت SSH نیز بسیار ساده است:

sudo apt update

sudo apt install fail2ban

سپس یک فایل تنظیمات محلی برای SSH ساختم:

sudo nano /etc/fail2ban/jail.d/sshd.local

و تنظیمات زیر را داخل آن قرار دادم:

[sshd] enabled = true

port = 52522

maxretry = 3

findtime = 10m

bantime = 1h

بعد Fail2ban را فعال کردم، چند تلاش ناموفق جالب را از طریق اتصال موبایلم برای آزمایش ایجاد کردم و وضعیت Jail مربوط به SSH را بررسی کردم:

sudo systemctl enable --now

fail2ban sudo fail2ban-client status sshd

Fail2ban آخرین مرحله از این سه گام برای متوقف‌کردن بات‌ها بود. می‌توان آن را به یک مأمور حراست شخصی برای سرور تشبیه کرد که پشت لایه‌های امنیتی قبلی می‌ایستد و بات‌های سمجی را که حاضر نیستند دست از تلاش بکشند، مسدود می‌کند.

Jump Box مربوط به SSH حالا تقریباً بدون مزاحمت بات‌ها کار می‌کند

حجم ترافیک مزاحم از یک سر و صدای دائمی به چند تلاش پراکنده کاهش پیدا کرد

من فقط به یک سرور ساده برای انجام کارهای روزمره نیاز داشتم، نه یک پروژه امنیتی جدید و پیچیده. اما متأسفانه همین که یک سرور جدید به اینترنت عمومی متصل می‌شود، حتی اگر فقط یک پورت SSH داشته باشد، به یک هدف بالقوه برای حمله تبدیل می‌شود.

سرور جدید من هم این موضوع را به‌خوبی ثابت کرد؛ تنها چند دقیقه پس از روشن‌شدن، با حجم زیادی از ترافیک بات‌ها مواجه شد.

انتقال SSH از پورت 22 باعث شد تعداد درخواست‌هایی که بات‌های اسکن‌کننده خودکار به سرور ارسال می‌کردند، به‌شکل چشمگیری کاهش پیدا کند.

استفاده از ورود فقط با کلید SSH نیز تهدید و دردسر مربوط به حدس‌زدن رمز عبور را از بین برد. درنهایت، Fail2ban هم برای بات‌های سمجی که همچنان به سرور حمله می‌کردند، یک مهلت یک‌ساعته در نظر گرفت و آن‌ها را موقتاً مسدود کرد.

البته هیچ‌کدام از این اقدامات باعث نمی‌شوند SSH شکست‌ناپذیر شود. بااین‌حال، من این سه مرحله ساده امن‌سازی را برای تک‌تک سرورهای لینوکسی که به اینترنت عمومی متصل می‌کنم انجام می‌دهم و به هرکسی که قصد انجام چنین کاری را دارد نیز توصیه می‌کنم همین اقدامات را درنظر بگیرد.

نمی‌توانم اینترنت را از حالت محیطی نامطمئن برای سرورهای Homelab خارج کنم. بات‌ها همچنان اسکن می‌کنند، نام‌های کاربری عجیب‌وغریب همچنان گاهی در لاگ‌ها ظاهر می‌شوند و سرورهای عمومی همیشه به احتیاط نیاز دارند.

اما با اجرای این مراحل امن‌سازی، می‌توانم سرورهایی را که در معرض اینترنت قرار دارند، به اهدافی بسیار کمتر جذاب برای بات‌ها تبدیل کنم.