امنیت

۱۰ قدم حیاتی امنیت سرور لینوکس — درست بعد از تحویل سرور

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

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

امنیت سرور لینوکس از کجا شروع می‌شود؟ سه دسته مهاجم

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

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

سوءاستفاده از آسیب‌پذیری عمومی. وقتی نقصی در OpenSSH یا وردپرس منتشر می‌شود، ظرف چند ساعت اسکنرها دنبال نسخه‌های وصله‌نشده می‌گردند. دفاع اینجا سرعت است.

پیکربندی اشتباه خودتان. دیتابیسی که روی همه‌ی اینترفیس‌ها گوش می‌دهد، داشبوردی بدون رمز، فایل بکاپی رهاشده در ریشه‌ی وب‌سرور. اینجا آسیب‌پذیری‌ای در کار نیست؛ سرور همان کاری را می‌کند که به آن گفته‌اید.

۱) سیستم را به‌روز کنید و وصله‌ی امنیتی را خودکار کنید

بیشتر نفوذهای موفق از آسیب‌پذیری‌هایی رخ می‌دهد که ماه‌ها قبل وصله شده‌اند اما کسی نصبشان نکرده:

apt update && apt upgrade -y

اما یک‌بار اجرا کردن امنیت نمی‌سازد؛ تکرار خودکارش می‌سازد. بسته‌ی unattended-upgrades با تنظیم پیش‌فرضش عملاً فقط وصله‌های امنیتی را نصب می‌کند — خط -updates در /etc/apt/apt.conf.d/50unattended-upgrades از ابتدا کامنت شده — یعنی ریسک شکستن سرویس‌ها کم است:

apt install unattended-upgrades -y
dpkg-reconfigure -plow unattended-upgrades
unattended-upgrade --dry-run --debug

# نمونه‌ی خروجی روی اوبونتو 24.04
Checking: openssh-server ([<Origin component:'main' archive:'noble-security' origin:'Ubuntu' label:'Ubuntu' site:'security.ubuntu.com' isTrusted:True>])
Packages that will be upgraded: openssh-server libssl3t64

نکته‌ای که اغلب از قلم می‌افتد: به‌روزرسانی هسته تا ریبوت نشدن سرور اعمال نمی‌شود. روی اوبونتو وجود فایل /var/run/reboot-required یعنی سرور منتظر ریبوت است، اما آن را قلاب بسته‌ی update-notifier-common می‌سازد که روی دبیان نیست؛ پس تنظیم زیر آنجا هرگز عمل نمی‌کند، مگر reboot-notifier را نصب کنید یا خودتان با needrestart -r l بررسی کنید:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
💡 چرا این قدم اول است: آسیب‌پذیری CVE-2024-6387 (regreSSHion) روی نسخه‌های ۸.۵ تا ۹.۷ در سیستم‌های مبتنی بر glibc اجازه‌ی اجرای کد از راه دور و بدون احراز هویت با دسترسی root می‌داد. سرورهای با وصله‌ی خودکار بی‌سروصدا بسته شدند؛ بقیه ماه‌ها باز ماندند.

روی اوبونتو LTS یک لایه‌ی رایگان دیگر هم هست: Ubuntu Pro تا پنج ماشین رایگان است و پشتیبانی امنیتی را از پنج سال روی Main به ده سال روی کل آرشیو می‌برد.

۲) با root کار نکنید — کاربر sudo بسازید

کار روزمره با root مثل جوشکاری بدون عینک است: هر اشتباه تایپی و هر اسکریپت کپی‌شده از اینترنت اختیار کامل سیستم را دارد.

adduser admin
usermod -aG sudo admin        # دبیان و اوبونتو
usermod -aG wheel admin       # آلما‌لینوکس و راکی

بقیه‌ی این راهنما دبیان و اوبونتو را فرض می‌گیرد؛ روی آلما‌لینوکس و راکی معادل‌ها dnf، firewalld و نام سرویس sshd به‌جای ssh است.

مزیت واقعی sudo فقط جلوگیری از اشتباه نیست، ردپاست: هر دستور با نام کاربر و زمان در ژورنال ثبت می‌شود — تنها راه پاسخ‌دادن به «چه کسی این را عوض کرد؟». NOPASSWD را کنار بگذارید؛ sudo بدون رمز یعنی هر فرایندی که با کاربر شما اجرا شود عملاً root است؛ بلوک‌های بعدی هم برای کوتاهی sudo ندارند.

۳) ورود با کلید SSH به‌جای رمز — مهم‌ترین قدم این فهرست

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

ssh-keygen -t ed25519 -C "laptop-1405"
ssh-copy-id admin@203.0.113.10

الگوریتم ed25519 امروز انتخاب پیش‌فرض است: کوتاه‌تر و سریع‌تر از RSA. حتماً عبارت عبور بگذارید — اگر لپ‌تاپتان گم شد، کلید را برای پیدا‌کننده بی‌ارزش می‌کند.

حالا ورود با رمز را ببندید

بعد از اینکه با کلید وارد شدید، در /etc/ssh/sshd_config:

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password

خط دوم را جدی بگیرید: روی دبیان و اوبونتو از قبل no است، اما روی توزیع‌های دیگر — یا اگر فایلی در sshd_config.d/ برش گردانده باشد — با بستن تنها PasswordAuthentication مسیر دومی برای رمز می‌ماند. صریح بنویسیدش و پیش از ری‌استارت اعتبارسنجی کنید:

sshd -t && systemctl restart ssh

به‌خاطر &&، اگر sshd -t خطای نحوی پیدا کند ری‌استارت اجرا نمی‌شود — همین عادت رایج‌ترین راه قفل‌شدن پشت در را می‌بندد. ری‌استارت sshd نشست‌های باز را قطع نمی‌کند. اگر sshd روی سرور شما سوکتی بالا می‌آید (بخش ۵)، به‌جایش systemctl restart ssh.socket بزنید.

⚠️ قانون طلایی هر تغییر SSH: ترمینال فعلی را نبندید؛ ورود جدید را در ترمینال دوم تست کنید تا اگر کار نکرد از اولی برگردانید. اگر پشت در ماندید، روی سرورهای ابری مهران هاست کنسول تحت وب VNC مستقل از SSH کار می‌کند — به شرطی که رمز کاربر را بلد باشید، چون کنسول کلید نمی‌پذیرد. روی سرورهای خارج همه‌جا چنین کنسولی نیست، پس پیش از بستن ورود با رمز مسیر اضطراری را بررسی کنید.

۴) کدام خط‌های sshd_config را واقعاً باید عوض کنید؟

سخت‌کردن sshd می‌تواند تا بی‌نهایت ادامه پیدا کند، اما بازدهی بعد از چند خط اول افت می‌کند. این‌ها همان چند خط است:

تنظیمپیش‌فرض رایجمقدار پیشنهادیچه دری را می‌بندد
PasswordAuthenticationyesnoکل حمله‌ی دیکشنری و رمزهای لو‌رفته را بی‌اثر می‌کند
KbdInteractiveAuthenticationno روی دبیان و اوبونتو (پیش‌فرض OpenSSH: yes)noمسیر دومِ رمز؛ یک فایل تکه‌ای در sshd_config.d/ بازش می‌کند
PermitRootLoginprohibit-passwordprohibit-password یا noورود مستقیم به تنها کاربری که نامش را همه می‌دانند
MaxAuthTries63تلاش در یک اتصال — هر کلیدی که کلاینت پیشنهاد می‌دهد یک تلاش است؛ با IdentitiesOnly yes فقط کلید درست را بفرستید
LoginGraceTime12020اتصال‌های نیمه‌باز که منابع sshd را اشغال می‌کنند
AllowUsersتعریف‌نشدهفهرست کاربران مجازورود هر کاربر دیگر سیستم، حتی با کلید درست
X11Forwardingyes (روی اوبونتو)noقابلیتی که روی سرور بدون محیط گرافیکی فقط سطح حمله است

بعد از ویرایش، به‌جای حدس‌زدن از خود sshd بپرسید؛ سوئیچ -T پیکربندی مؤثر نهایی را چاپ می‌کند:

sshd -T | grep -Ei 'passwordauth|permitroot|maxauthtries|kbdinteractive'

maxauthtries 3
permitrootlogin prohibit-password
passwordauthentication no
kbdinteractiveauthentication no

یک هشدار: بسیاری از توزیع‌های امروزی فایل‌های تکه‌ای در /etc/ssh/sshd_config.d/ می‌گذارند و خط Include ابتدای فایل اصلی آن‌ها را زودتر می‌خواند. چون در OpenSSH اولین مقدارِ خوانده‌شده برنده است، تنظیم انتهای فایل اصلی ممکن است هرگز اعمال نشود.

۵) تغییر پورت SSH چقدر کمک می‌کند — و چرا روی اوبونتوی امروز به‌تنهایی اثر نمی‌کند؟

اول صادق باشیم: بردن SSH از پورت ۲۲ به ۲۲۲۲ امنیت واقعی نمی‌سازد و هر اسکنر جدی سرویس را پیدا می‌کند. کارش حذف اسکن‌های انبوه — که فقط پورت ۲۲ را می‌زنند — از لاگ‌هاست. وقتی چند هزار خط «رمز اشتباه» در روز نداشته باشید، آن یک خط غیرعادی به چشم می‌آید.

اما اینجا تله‌ای هست که ساعت‌ها وقت می‌گیرد. از اوبونتو ۲۲.۱۰ به بعد sshd با فعال‌سازی سوکتی بالا می‌آید: ssh.socket پورت را نگه می‌دارد و فقط هنگام رسیدن اتصال sshd را اجرا می‌کند؛ پس عوض‌کردن Port و ری‌استارت ssh.service هیچ اتفاقی نمی‌اندازد. اول ببینید در کدام حالت هستید:

systemctl is-enabled ssh.socket
enabled

ss -tlnp '( sport = :22 )'
State  Recv-Q Send-Q  Local Address:Port  Peer Address:Port  Process
LISTEN 0      4096          0.0.0.0:22         0.0.0.0:*      users:(("systemd",pid=1,fd=78))

آن pid=1 امضای ماجراست: پورت را systemd نگه داشته، نه sshd. در اوبونتو ۲۴.۰۴ یک تولیدکننده‌ی systemd پورت را پویا از sshd_config می‌خواند، اما فقط وقتی واحد سوکت را بازخوانی و ری‌استارت کنید.

در اوبونتو ۲۶.۰۴ LTS هم فعال‌سازی سوکتی پیش‌فرض است؛ آنجا OpenSSH نسخه‌ی ۱۰.۲ است و نام مستعار تازه‌ی sshd.service برای ssh.service اضافه شده — اگر اسکریپت یا فیلتری به نام واحد بند است، بازبینی‌اش کنید. در همان نسخه sudo-rs جای sudo پیش‌فرض را گرفته، اما نام گروه هنوز sudo است و دستورهای بخش ۲ تغییر نمی‌کنند.

خودِ پورت را در /etc/ssh/sshd_config با خط Port 2222 بنویسید — بقیه‌ی راهنما همین ۲۲۲۲ را فرض می‌گیرد — و بعد یکی از این دو مسیر را بروید:

# /etc/ssh/sshd_config
Port 2222

systemctl daemon-reload
systemctl restart ssh.socket        # اعمال پورت جدید در حالت سوکتی

# یا بازگشت کامل به سرویس کلاسیک
systemctl disable --now ssh.socket
rm -f /etc/systemd/system/ssh.service.d/00-socket.conf
rm -f /etc/systemd/system/ssh.socket.d/addresses.conf
systemctl daemon-reload
systemctl enable --now ssh.service

آن دو فایل drop-in را حتماً بردارید؛ تا وقتی 00-socket.conf سر جایش است اوبونتو ssh.service را به سوکت بند نگه می‌دارد و بازگشت رخ نمی‌دهد. بعد با ss -tlnp '( sport = :2222 )' تأیید کنید که این بار خودِ sshd پورت را گرفته، نه pid=1.

⚠️ ترتیب کارها حیاتی است: اگر فایروال روشن است، اول پورت جدید را در آن باز کنید، بعد سوکت یا سرویس را ری‌استارت کنید و بعد در ترمینال دوم تست کنید. برعکسش یعنی سرور روی پورت جدید گوش می‌دهد و فایروال آن را بسته نگه داشته.

۶) فایروال UFW: هر چیزی که آگاهانه باز نکرده‌اید، بسته باشد

ابزار ufw ساده‌ترین راه رسیدن به سیاست «همه‌چیز بسته مگر خلافش» است. هنگام نصب غیرفعال است و تا enable نکنید اعمال نمی‌شود:

apt install ufw -y
ufw default deny incoming
ufw default allow outgoing
ufw limit 2222/tcp comment 'ssh'
ufw allow 80,443/tcp comment 'web'
ufw --force enable

ufw enable ساده روی یک نشست SSH می‌پرسد «Command may disrupt existing ssh connections» و منتظر می‌ماند؛ اگر کل بلوک را یک‌جا پیست کنید، خط بعدی به‌جای شما جواب می‌دهد؛ --force را فقط وقتی بزنید که قانون پورت SSH را بالاتر اضافه کرده باشید. برای SSH هم limit گذاشتیم نه allow: هر آی‌پی که در ۳۰ ثانیه شش اتصال آغاز کند پیش از رسیدن به sshd مسدود می‌شود. سرویس‌های خصوصی را هم به آی‌پی خودتان ببندید:

ufw allow from 203.0.113.5 to any port 5432 proto tcp comment 'db from office'
ufw status verbose

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
2222/tcp                   LIMIT IN    Anywhere                   # ssh
80,443/tcp                 ALLOW IN    Anywhere                   # web
5432/tcp                   ALLOW IN    203.0.113.5                # db from office
2222/tcp (v6)              LIMIT IN    Anywhere (v6)              # ssh
80,443/tcp (v6)            ALLOW IN    Anywhere (v6)              # web

دو نکته‌ی این خروجی را بخوانید: disabled (routed) یعنی فوروارد آی‌پی خاموش است — روی سروری که داکر دارد همین خط deny (routed) می‌شود. ردیف‌های (v6) قرینه‌ی IPv6 همان قانون‌اند؛ اگر نمی‌بینیدشان یعنی IPV6=yes در /etc/default/ufw خاموش است و فایروال فقط IPv4 را می‌بندد.

⚠️ اگر داکر روی این سرور دارید: داکر و ufw ناسازگارند: پورتی که با -p 8080:80 منتشر می‌کنید در جدول nat پیش از زنجیره‌های ufw منحرف می‌شود. نتیجه اینکه ufw deny 8080 بی‌اثر است و آن پورت از کل اینترنت باز می‌ماند، در حالی که ufw status اطمینان کاذب می‌دهد. راه‌حل: پورتی را که فقط خود سرور لازم دارد به‌شکل 127.0.0.1:8080:80 منتشر کنید — الگویی که در راهنمای داکر روی سرور ابری باز شده است.

۷) Fail2ban؛ و تله‌ای که روی دبیان ۱۲ سرویس را بالا نمی‌آورد

Fail2ban لاگ‌ها را می‌خواند و هر آی‌پی با تلاش ناموفق بیش از حد را مدتی روی فایروال مسدود می‌کند. jail.conf را دست نزنید — با هر به‌روزرسانی بازنویسی می‌شود؛ تنظیماتتان را در jail.local بنویسید و سرویس را بعد از آن ری‌استارت کنید:

apt install fail2ban python3-systemd -y

# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 4

[sshd]
enabled      = true
backend      = systemd
port         = 2222
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd + _COMM=sshd-session

systemctl restart fail2ban

چهار تلاش ناموفق در ده دقیقه و یک ساعت مسدودی: برای مهاجم خودکار کافی، و آن‌قدر کوتاه که مسدودی اشتباهی خودتان بدون تیکت باز شود. backend = systemd را هم عمداً داخل [sshd] نوشتیم: در [DEFAULT] — کاری که خود دبیان از نسخه‌ی 1.0.2-3 در jail.d/defaults-debian.conf می‌کند — همه‌ی jailها سراغ ژورنال می‌روند و آن‌هایی که لاگشان فایل است (وردپرس، آپاچی، پنل) «enabled» گزارش می‌دهند و بی‌سروصدا هیچ‌کس را مسدود نمی‌کنند.

fail2ban-client status sshd

Status for the jail: sshd
|- Filter
|  |- Currently failed: 2
|  |- Total failed:     3184
|  `- Journal matches:  _SYSTEMD_UNIT=ssh.service + _COMM=sshd + _COMM=sshd-session
`- Actions
   |- Currently banned: 7
   |- Total banned:     412
   `- Banned IP list:   203.0.113.44 198.51.100.77 192.0.2.19

عدد Total failed مهم‌ترین چیزی است که باید ببینید: اگر بعد از چند ساعت روی صفر مانده، فیلتر چیزی نمی‌بیند و jail فقط تزئینی است. رفع مسدودی یک دستور است: fail2ban-client set sshd unbanip 203.0.113.5

⚠️ تله‌ی دبیان ۱۲: اگر سرویس بالا نیامد و «Have not found any log file for sshd jail» دیدید، مشکل از پیکربندی شما نیست: از دبیان ۱۲ rsyslog پیش‌فرض نصب نمی‌شود، پس /var/log/auth.log وجود ندارد و لاگ‌ها فقط در ژورنال‌اند. راه‌حل ثبت‌شده در باگ ۱۰۳۷۴۳۷ دبیان همان بلوک بالاست. خط journalmatch را هم بی‌دلیل صریح ننوشتیم: طبق باگ ۱۰۶۱۷۷۶، نسخه‌ی 1.0.2-2 بوک‌ورم در filter.d/sshd.conf نام واحد را sshd.service نوشته و در دبیان ssh.service است؛ فعلاً شاخه‌ی _COMM=sshd نجاتش می‌دهد، اما از OpenSSH ۹.۸ به بعد فرایند هر نشست sshd-session نام دارد و آن شاخه هم می‌خشکد. دبیان ۱۳ با 1.1.0 این خط را از ابتدا درست دارد.

۸) سرویس‌های اضافه و پورت‌های باز: سطح حمله را کوچک کنید

هر پورتی که روی اینترفیس عمومی گوش می‌دهد، یک درِ بالقوه است:

ss -tulpn

Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
tcp   LISTEN 0      128          0.0.0.0:2222       0.0.0.0:*     users:(("sshd",pid=812,fd=3))
tcp   LISTEN 0      511          0.0.0.0:80         0.0.0.0:*     users:(("nginx",pid=1330,fd=6))
tcp   LISTEN 0      511             [::]:80            [::]:*     users:(("nginx",pid=1330,fd=7))
tcp   LISTEN 0      80           0.0.0.0:3306       0.0.0.0:*     users:(("mariadbd",pid=1104,fd=23))
tcp   LISTEN 0      511        127.0.0.1:6379       0.0.0.0:*     users:(("redis-server",pid=944,fd=6))
udp   UNCONN 0      0      127.0.0.53%lo:53         0.0.0.0:*     users:(("systemd-resolve",pid=701,fd=13))

ستون آدرس محلی مهم‌ترین ستون است. 127.0.0.1 یعنی سرویس فقط از داخل سرور در دسترس است — ردیس در مثال بالا امن است. اما 0.0.0.0 یعنی از کل اینترنت، و [::] معادل IPv6 همان است؛ پس فقط دنبال 0.0.0.0 نگردید. ردیف MariaDB اشتباه کلاسیک است — دیتابیس دلیلی برای دیده‌شدن از بیرون ندارد: در /etc/mysql/mariadb.conf.d/50-server.cnf مقدار bind-address را 127.0.0.1 بگذارید. همین منطق برای هر داشبورد بدون احراز هویت هم هست.

systemctl list-units --type=service --state=running
systemctl disable --now rpcbind.socket rpcbind.service   # سوکت را هم ببندید
apt purge vsftpd -y

همان تله‌ی بخش ۵ اینجا هم هست: بعضی سرویس‌ها واحد .socket جدا دارند و اگر فقط .service را غیرفعال کنید، اولین اتصال دوباره بالایش می‌آورد. سرویس بی‌استفاده را کامل بردارید.

۹) بکاپ: بدترین سناریو «داده رفت» است، نه «سرور هک شد»

سروری که هک شده را می‌شود دوباره ساخت؛ داده‌ای که رفته را نه. در پنل سرورهای ابری ایران پشتیبان‌گیری خودکار یک افزودنی است: اگر در موقعیت سرورتان در دسترس باشد با یک کلید فعالش می‌کنید و ساعتی حساب می‌شود؛ بازگردانی چون کل دیسک را بازنویسی می‌کند از راه تیکت پشتیبانی انجام می‌شود. روی سرورهای خارج بستگی به ارائه‌دهنده دارد و همه‌جا نیست. به هیچ‌کدام اکتفا نکنید:

0 3 * * * /usr/bin/rsync -az /var/www/ backup@198.51.100.20:/srv/backup/www/

# روی سرور بکاپ، در authorized_keys کاربر backup
# (rrsync از rsync 3.2.4 به بعد در /usr/bin نصب می‌شود)
restrict,command="rrsync -wo -no-del /srv/backup/www" ssh-ed25519 AAAA…

دو نکته بیشتر بکاپ‌ها را بی‌فایده می‌کند. اول: اگر همان سرور بتواند روی مقصد پاک کند، بکاپ شما هم در دسترس مهاجم است — کاری که باج‌افزارها اول انجام می‌دهند. نیاوردن --delete از خط cron هیچ محافظتی نمی‌سازد؛ کسی که سرور را گرفته همان کلید را دارد. محدودیت باید سمت مقصد باشد: خط دوم بلوک بالا کلید را به یک دستور اجباری می‌بندد که فقط می‌نویسد و هیچ حذفی نمی‌پذیرد. بهتر از آن: اسنپ‌شات نسخه‌داری که سرور مبدأ به آن دسترسی ندارد. دوم: بکاپی که یک‌بار بازیابی آزمایشی نشده، بکاپ نیست، فرضیه است؛ ماهی یک‌بار یک فایل تصادفی را برگردانید — جزئیات در آموزش بکاپ‌گیری از سرور لینوکس.

۱۰) لاگ‌خوانی و پایش: از کجا بفهمم سرورم هک شده؟

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

journalctl -t sshd -t sshd-session --since today | grep -cE 'Failed password|Invalid user|Connection closed by (invalid|authenticating) user'
loginctl list-sessions        # چه کسی همین حالا وصل است
last -20                      # ورودهای موفق اخیر

عمداً به‌جای -u ssh روی شناسه‌ی سرویس فیلتر کردیم: نام واحد بین توزیع‌ها فرق دارد و از OpenSSH ۹.۸ به بعد هر نشست را فرایند sshd-session می‌نویسد. اگر روی اوبونتو ۲۵.۱۰ یا ۲۶.۰۴ هستید، who و lastb را هم فراموش کنید: systemd آنجا بدون پشتیبانی utmp ساخته می‌شود (سرریز ۲۰۳۸)، پس who خالی است، last از پایگاه جدید wtmpdb می‌خواند و lastb و btmp وجود ندارند.

اگر ورود با رمز را در بخش ۳ بسته‌اید، sshd دیگر خط Failed password تولید نمی‌کند و تلاش‌ها به‌شکل Invalid user ثبت می‌شوند — پس صفر دیدن را «هیچ حمله‌ای نیست» معنی نکنید. اگر شک دارید، سراغ نشانه‌های ماندگاری بروید؛ مهاجم تقریباً همیشه کاربر جدید می‌سازد، کلید عمومی خودش را اضافه می‌کند یا کرون‌جابی می‌گذارد:

awk -F: '$3 == 0 {print $1}' /etc/passwd          # هر کاربر با UID صفر جز root مشکوک است
cat ~/.ssh/authorized_keys /root/.ssh/authorized_keys
for u in $(cut -d: -f1 /etc/passwd); do crontab -lu "$u" 2>/dev/null; done
ps aux --sort=-%cpu | head -5
ss -tunp state established

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

💡 اگر واقعاً نفوذی پیدا کردید، سرور را «تمیز» نکنید. نمی‌دانید مهاجم چه چیز دیگری جا گذاشته — باینری جایگزین‌شده، ماژول هسته، کلیدی در کاربری که ندیده‌اید. راه درست: سرور را از شبکه جدا کنید، داده‌ها را بیرون بکشید، سیستم‌عامل را از نو نصب کنید و رمزها و کلیدها را عوض کنید.

لایه‌ی آخر پایش از بیرون است: ابزار رایگان تست سرعت و سلامت سایت اعتبار گواهی SSL را بررسی می‌کند و اگر پشت CDN باشید نشان می‌دهد آی‌پی سرور اصلی از روی رکوردهای عمومی دامنه قابل کشف است یا نه. پنهان‌ماندن آی‌پی مبدأ پشت CDN مهران هاست یک لایه پیش از فایروال است، اما مطلق نیست: رکورد قدیمی‌ای مثل mail که هنوز به سرور اصلی اشاره می‌کند، همان آدرس را لو می‌دهد.

۱۱) امنیت روی هاست اشتراکی چه فرقی دارد؟

اگر سایتتان روی هاست اشتراکی cPanel یا دایرکت‌ادمین است، بیشتر این فهرست وظیفه‌ی شما نیست: هسته، sshd، فایروال سرور و سخت‌سازی سیستم‌عامل کارِ ارائه‌دهنده است. در عوض تقریباً همه‌ی نفوذها اینجا از سمت اپلیکیشن می‌آید: افزونه یا قالب وردپرسی که ماه‌هاست به‌روز نشده، رمز ضعیف پنل، فایل‌های نصب و بکاپ رهاشده.

یک نکته‌ی مرزی: پنل فارسی مهران هاست صندوق‌های ایمیل (ساخت، حذف، تغییر رمز، سهمیه) و فورواردرها را مدیریت می‌کند، اما رکوردهای احراز اصالت ایمیل مثل SPF و DKIM و DMARC را نمی‌سازد؛ آن‌ها را باید به‌صورت رکورد TXT در بخش DNS دامنه بنویسید. مرز دقیق مسئولیت‌ها در مقایسه‌ی هاست اشتراکی و سرور مجازی آمده است.

چک‌لیست جمع‌وجور

قدمابزارزمان
به‌روزرسانی + وصله خودکارapt, unattended-upgrades۵ دقیقه
کاربر sudoadduser, usermod۲ دقیقه
کلید SSH + بستن رمزssh-keygen, sshd_config۱۰ دقیقه
سخت‌کردن sshdsshd -t, sshd -T۱۰ دقیقه
پورت جدید SSHsshd_config, ssh.socket۵ دقیقه
فایروالUFW۵ دقیقه
ضد حدس رمزFail2ban۵ دقیقه
حذف سرویس اضافهss, systemctl۱۰ دقیقه
بکاپ + تست بازیابیپنل، rsync، cron۱۵ دقیقه
لاگ‌خوانیjournalctl, loginctl, psمستمر
مانیتورینگنمودارهای مصرف پنل + یک سرویس آپتایم بیرونی۵ دقیقه

امنیت مقصد نیست، عادت است — اما همین فهرست شما را از دسته‌ی «هدف آسانِ اسکریپت‌های خودکار» بیرون می‌آورد. قدم بعدی؟ وب‌سایت‌تان را با Nginx و HTTPS بالا بیاورید.

سؤالات پرتکرار

مهم‌ترین قدم امنیت سرور لینوکس چیست؟

جایگزین‌کردن رمز عبور با کلید SSH، بی‌رقیب مهم‌ترین قدم است. بیشترین حجم حمله‌ای که به هر سرور عمومی می‌خورد حدس خودکار رمز است و بستن این مسیر کل آن دسته را بی‌اثر می‌کند. یک کلید ed25519 بسازید، روی سرور بگذارید، ورود موفق را در ترمینالی جدا تست کنید و بعد در sshd هم احراز هویت با رمز و هم احراز هویت تعاملی صفحه‌کلید را ببندید.

تغییر پورت SSH واقعاً امنیت را بالا می‌برد؟

نه به‌عنوان لایه‌ی امنیتی واقعی؛ هر اسکنر جدی همه‌ی پورت‌ها را می‌زند و سرویس را پیدا می‌کند. فایده‌اش عملیاتی است: اسکن‌های انبوهی که فقط پورت ۲۲ را امتحان می‌کنند از لاگ‌ها حذف می‌شوند و رویداد مشکوک واقعی دیده می‌شود. در اوبونتو ۲۲.۱۰ به بعد — تا همین ۲۶.۰۴ LTS — که sshd سوکتی بالا می‌آید، تغییر پورت بدون ری‌استارت واحد سوکت اعمال نمی‌شود.

با وجود ورود کلیدی، هنوز به Fail2ban نیاز دارم؟

برای خود SSH ارزشش کم می‌شود، چون تلاش‌هایی که مسدود می‌کند از ابتدا هم نمی‌توانستند موفق شوند. اما Fail2ban جایی مفید می‌ماند که سرویسی با رمز عبور دارید: ورود وردپرس، پنل مدیریت، سرویس ایمیل، یا هر فرم ورودی در معرض اینترنت. یک قانون limit روی فایروال هم همین کار را پیش از رسیدن ترافیک به سرویس انجام می‌دهد.

از کجا بفهمم سرور لینوکسم هک شده است؟

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

روی هاست اشتراکی هم باید این کارها را انجام داد؟

خیر، بخش زیربنایی این فهرست وظیفه‌ی ارائه‌دهنده است: هسته، پیکربندی sshd، فایروال سرور و سخت‌سازی سیستم‌عامل خارج از دسترس کاربر هاست اشتراکی‌اند. سهم شما لایه‌ی اپلیکیشن است و بیشترین نفوذها هم همان‌جا رخ می‌دهد: به‌روز نگه‌داشتن هسته و افزونه‌های CMS، رمزهای یکتا برای پنل و پایگاه داده، حذف فایل‌های نصب و بکاپ رهاشده، و فعال‌کردن ورود دومرحله‌ای.

آموزش‌های مرتبط

آماده‌ی تمرین عملی هستید؟

سرور ابری ساعتی مهران هاست در ۶۰ ثانیه تحویل می‌شود — تمرین کنید و فقط بابت همان ساعت‌ها پرداخت کنید. هزینه را پیش از ثبت‌نام با محاسبه‌گر برآورد کنید.