الانتقال إلى المحتوى

تحصين خادم Linux VPS: دليل عملي كامل

تحصين خطوة بخطوة لخادم Ubuntu أو Debian أو RHEL مكشوف على الإنترنت: SSH، وجدران الحماية، وإعدادات النواة، والعزل، والتدقيق، ومراقبة السلامة، والنسخ الاحتياطي، والتحقق.

ABYSSS Security Teamقراءة 20 دقيقة

خادم افتراضي تحيط به حلقات لمفاتيح SSH والنواة وجدار الحماية والتدقيق، مع إيقاف الهجمات عند الحافة.
المحتويات

المقدمة

يتعرض الخادم الافتراضي الخاص الجديد ذو عنوان IP العام للفحص خلال دقائق من تشغيله. تجرب الروبوتات الآلية بيانات الاعتماد الافتراضية عبر SSH، وتبحث عن قواعد البيانات ولوحات الإدارة المكشوفة، وتطلق عمليات استغلال ضد كل إطار ويب شائع. لا شيء من هذا موجه، ولهذا تحديدًا ينجح: يكفي المهاجم خادم واحد أهمل الأساسيات. يشرح هذا الدليل تحصين خادم Linux VPS من أول تسجيل دخول إلى التحقق المستمر، مع أوامر كل خطوة وأدوات فحص عملك.

أول تسجيل دخول: التحديث والجرد وضبط الساعة

قبل أي تحصين، حدّث النظام وسجل حالته. فصور المزودين كثيرًا ما تكون قديمة بأسابيع، والجرد الذي تأخذه الآن هو خط الأساس الذي ستقارن به أثناء أي حادثة.

التحديث وخط الأساس · Ubuntu وDebian
sudo apt update && sudo apt full-upgrade -y
sudo apt autoremove --purge -y
[ -f /var/run/reboot-required ] && sudo reboot

# RHEL, Rocky, Alma
sudo dnf upgrade --refresh -y
sudo needs-restarting -r || sudo reboot
الهوية والوقت ونظرة أولى على الانكشاف
sudo hostnamectl set-hostname web-01.example.com
sudo timedatectl set-timezone UTC
timedatectl status            # "System clock synchronized: yes"

sudo ss -tulpn                # every listening socket and its process
systemctl list-units --type=service --state=running
last -n 20; sudo lastb -n 20  # recent and failed logins
cat /etc/os-release; uname -r

استخدم UTC على الخوادم. فسجلات الأجهزة في مناطق مختلفة لا تتطابق أثناء التحقيق إلا إذا شاركت ساعة واحدة، والوقت الصحيح مهم أيضًا لـ TLS وKerberos ورموز TOTP. يستخدم Ubuntu وDebian أداة systemd-timesyncd افتراضيًا، أما chrony فخيار أفضل للخوادم التي تحتاج إلى دقة أكبر وهي الافتراضية في RHEL.

المستخدمون وsudo وسياسة كلمات المرور

لا تعمل أبدًا بحساب root. أنشئ مسؤولًا باسم محدد لكل شخص، وامنحه sudo عبر مجموعة، واقفل كلمة مرور root ليكون الطريق الوحيد إلى root عبر استدعاء sudo مدقق.

إنشاء مستخدم مسؤول وقفل root
sudo adduser alice                       # Debian and Ubuntu
sudo usermod -aG sudo alice              # use "wheel" on RHEL
sudo groupadd sshusers && sudo usermod -aG sshusers alice

sudo passwd -l root                      # lock the root password
sudo chage -l alice                      # check password ageing

شدد إعدادات sudo بملف مستقل بدل تعديل ملف sudoers الرئيسي. وعدّل دائمًا عبر visudo، فهو يرفض حفظ ملف فيه أخطاء صياغة قد تمنع كل المسؤولين من sudo.

/etc/sudoers.d/10-hardening · عدّله باستخدام visudo -f
Defaults use_pty
Defaults logfile="/var/log/sudo.log"
Defaults log_input, log_output
Defaults timestamp_timeout=5
Defaults passwd_tries=3
Defaults !visiblepw

يمنع خيار use_pty أي عملية في الخلفية من حقن ضغطات مفاتيح في طرفيتك بعد انتهاء sudo. ويسجل تسجيل الإدخال والإخراج جلسات sudo كاملة في /var/log/sudo-io، ويمكن إعادة تشغيلها عبر sudoreplay أثناء التحقيق. وحتى مع SSH بالمفاتيح فقط، ما زالت كلمات المرور المحلية تحمي sudo، فضع سياسة معقولة.

/etc/security/pwquality.conf و/etc/login.defs
# /etc/security/pwquality.conf   (apt install libpam-pwquality)
minlen = 14
minclass = 3
maxrepeat = 3
dictcheck = 1
enforce_for_root

# /etc/login.defs
PASS_MAX_DAYS   365
PASS_MIN_DAYS   1
PASS_WARN_AGE   14
UMASK           027

ابحث عن كل ما لا ينبغي له تسجيل الدخول وأزله: الحسابات غير المستخدمة، والحسابات ذات كلمات المرور الفارغة، وأي حساب غير root له UID 0.

مراجعة الحسابات
awk -F: '$3 == 0 {print $1}' /etc/passwd          # only "root" expected
sudo awk -F: '$2 == "" {print $1}' /etc/shadow      # empty passwords
awk -F: '$7 !~ /(nologin|false)$/ {print $1, $7}' /etc/passwd
sudo usermod -s /usr/sbin/nologin olduser && sudo usermod -L olduser

SSH: مفاتيح فقط، دون root، وتشفير حديث

SSH هو الباب الأمامي لمعظم خوادم VPS، والمصادقة بكلمة المرور هي ما تهاجمه الروبوتات باستمرار. انتقل إلى المصادقة بالمفاتيح، ويفضل بمفتاح عتادي، ثم أوقف كلمات المرور تمامًا.

على جهازك: أنشئ مفتاحًا وثبّته
ssh-keygen -t ed25519 -a 100 -C "alice@laptop"
# or, with a FIDO2 security key such as a YubiKey:
ssh-keygen -t ed25519-sk -O resident -O verify-required -C "alice@yubikey"

ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@203.0.113.10
ssh alice@203.0.113.10        # confirm key login works BEFORE disabling passwords

ضع إعداداتك في ملف مستقل. في Ubuntu وDebian، يتضمن sshd_config المسار /etc/ssh/sshd_config.d/*.conf في بدايته، ويحتفظ sshd بأول قيمة يقرؤها لكل خيار، لذلك يتغلب ملف باسم 10-hardening.conf على ملف 50-cloud-init.conf الذي تأتي به صور سحابية كثيرة مع تفعيل PasswordAuthentication.

/etc/ssh/sshd_config.d/10-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
PermitEmptyPasswords no
AllowGroups sshusers

MaxAuthTries 3
MaxSessions 4
LoginGraceTime 20
ClientAliveInterval 300
ClientAliveCountMax 2

X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no
PermitUserEnvironment no
LogLevel VERBOSE

KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
HostKeyAlgorithms ssh-ed25519,sk-ssh-ed25519@openssh.com,rsa-sha2-512,rsa-sha2-256

يسجل LogLevel VERBOSE بصمة المفتاح المستخدم في كل تسجيل دخول، مما يوضح أي مفتاح، وبالتالي أي شخص أو نظام، فتح الجلسة. وإذا احتجت إلى تمرير TCP لخادم وسيط أو نفق قاعدة بيانات، ففعّله لتلك المجموعة فقط بكتلة Match بدل تفعيله عامًا.

تحقق ثم أعد التحميل دون فقدان جلستك
sudo sshd -t                                  # syntax check, silent on success
sudo sshd -T | grep -Ei 'permitrootlogin|passwordauth|kbdinteractive|allowgroups'
sudo systemctl reload ssh                     # "sshd" on RHEL

# Keep this session open. From a SECOND terminal:
ssh alice@203.0.113.10                        # must succeed
ssh -o PubkeyAuthentication=no alice@203.0.113.10   # must be refused

أزل مفاتيح المضيف الضعيفة ومجموعات Diffie-Hellman القصيرة. سيحذر العملاء من تغير مفتاح المضيف إذا أعدت توليد المفاتيح، لذا افعل ذلك في اليوم الأول وشارك البصمات الجديدة مع فريقك.

مفاتيح المضيف وmoduli
sudo rm -f /etc/ssh/ssh_host_*
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""

sudo awk '$5 >= 3071' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.safe >/dev/null
sudo mv /etc/ssh/moduli.safe /etc/ssh/moduli
sudo systemctl restart ssh

for k in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$k"; done

الخيار الأقوى هو إزالة SSH من الإنترنت العام تمامًا. ضع المسؤولين على شبكة WireGuard أو Tailscale، واربط sshd بتلك الواجهة عبر ListenAddress، واسمح بالمنفذ 22 فقط من نطاق VPN. عندها لا تصل حركة التخمين إلى الخدمة أبدًا. تحقق من الإعداد النهائي من جهازك باستخدام ssh-audit، الذي يقيّم تبادل المفاتيح والتشفير وMAC ومفاتيح المضيف وينبه إلى كل ما هو ضعيف.

دقق إعدادات SSH من الخارج
pipx install ssh-audit
ssh-audit 203.0.113.10
ssh-audit -p 2222 203.0.113.10      # if you changed the port

جدار الحماية: المنع افتراضيًا

اسمح فقط بالمنافذ التي يوجد الخادم من أجلها، وامنع كل ما عداها في الدخول، وتأكد من أن القواعد تغطي IPv6 وIPv4. استخدم طبقتين إن أمكن: يوقف جدار حماية المزود أو مجموعة الأمان الحركة قبل وصولها إلى الجهاز، ويحميك جدار حماية الخادم إذا أُسيء ضبط قاعدة السحابة.

UFW على Ubuntu وDebian
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw limit 22/tcp comment 'SSH, rate limited'
sudo ufw allow 80,443/tcp comment 'Web'
# admin access from one network only:
# sudo ufw allow from 198.51.100.0/24 to any port 22 proto tcp
grep IPV6 /etc/default/ufw                # must be IPV6=yes
sudo ufw enable
sudo ufw status verbose numbered

تحظر قاعدة limit العنوان الذي يفتح ستة اتصالات أو أكثر خلال 30 ثانية، مما يبطئ التخمين دون برامج إضافية. وإذا كنت تفضل إدارة القواعد مباشرة، فإن nftables هو جدار حماية النواة الحديث في كل التوزيعات الحالية، وجدول inet واحد يغطي IPv4 وIPv6 معًا.

/etc/nftables.conf · ثم: sudo nft -c -f /etc/nftables.conf && sudo systemctl enable --now nftables
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
  set ssh_ratelimit {
    type ipv4_addr
    flags dynamic, timeout
    timeout 1m
  }

  chain input {
    type filter hook input priority 0; policy drop;

    ct state established,related accept
    ct state invalid drop
    iif "lo" accept

    ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } limit rate 10/second accept
    ip6 nexthdr icmpv6 icmpv6 type { echo-request, destination-unreachable, packet-too-big, time-exceeded, parameter-problem, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept

    tcp dport 22 ct state new add @ssh_ratelimit { ip saddr limit rate over 10/minute } drop
    tcp dport 22 accept
    tcp dport { 80, 443 } accept

    limit rate 5/minute log prefix "nft-drop: " level info
  }

  chain forward {
    type filter hook forward priority 0; policy drop;
  }

  chain output {
    type filter hook output priority 0; policy accept;
  }
}

لا تحظر اكتشاف الجيران في ICMPv6 أو رسائل packet-too-big، فلا يعمل IPv6 دونها. وفي أنظمة عائلة RHEL، تعد firewalld الواجهة المدعومة. أزل الخدمات غير اللازمة من المنطقة الافتراضية، لأن الصور السحابية كثيرًا ما تسمح بـ cockpit وdhcpv6-client مسبقًا.

firewalld على RHEL وRocky وAlma
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --permanent --remove-service=cockpit
sudo firewall-cmd --permanent --remove-service=dhcpv6-client
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=198.51.100.0/24 service name=ssh accept'
sudo firewall-cmd --permanent --remove-service=ssh     # after the rich rule is in place
sudo firewall-cmd --reload && sudo firewall-cmd --list-all

تستحق تصفية الخروج الجهد على الخوادم ذات المهمة المحددة. فنادرًا ما يحتاج خادم الويب إلى فتح اتصالات خارجة على منافذ عشوائية، وحظرها يوقف كثيرًا من الصدفات العكسية ومعدّني العملات وأدوات تسريب البيانات. ابدأ بتسجيل الحركة الخارجة لمدة أسبوع، ثم اسمح فقط بـ DNS وNTP ومرايا الحزم وواجهات API التي يستدعيها التطبيق فعلًا.

الحماية من التخمين: Fail2ban أو CrowdSec

يراقب Fail2ban السجلات بحثًا عن المحاولات الفاشلة المتكررة ويحظر عنوان المصدر في جدار الحماية. ومع SSH بالمفاتيح فقط يقل أثر الحظر على الأمن، لكنه يقلل حجم السجلات ويحمي الخدمات التي ما زالت تقبل كلمات المرور، مثل تسجيل الدخول إلى الويب والبريد.

/etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
bantime.increment = true
bantime.maxtime   = 1w
backend   = systemd
banaction = nftables-multiport
ignoreip  = 127.0.0.1/8 ::1 198.51.100.0/24

[sshd]
enabled = true
mode    = aggressive

[nginx-http-auth]
enabled = true
تثبيت Fail2ban وتشغيله
sudo apt install fail2ban         # RHEL: sudo dnf install epel-release fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 192.0.2.44

CrowdSec بديل حديث. فهو يحلل السجلات بسيناريوهات مجتمعية، وينفذ قراراته عبر bouncers في جدار الحماية أو الوكيل العكسي، ويشارك إشارات هجوم مجهولة الهوية لتتمكن من حظر العناوين التي هاجمت أعضاء آخرين قبل أن تصل إليك. ثبّت المحرك من مستودع حزمه وأضف bouncer جدار حماية nftables.

محرك CrowdSec وbouncer جدار الحماية
curl -s https://install.crowdsec.net | sudo sh      # adds the repository; read it first
sudo apt install crowdsec crowdsec-firewall-bouncer-nftables
sudo cscli collections install crowdsecurity/linux crowdsecurity/sshd crowdsecurity/nginx
sudo cscli metrics
sudo cscli decisions list
sudo cscli alerts list

التحديثات الأمنية وإعادة التشغيل التلقائية

تُخترق معظم الخوادم عبر ثغرات كان لها تحديث بالفعل. ثبّت التحديثات الأمنية تلقائيًا، وجدول إعادة التشغيل لتعمل النوى والمكتبات الجديدة فعلًا.

unattended-upgrades على Ubuntu وDebian
sudo apt install unattended-upgrades apt-listchanges needrestart
sudo dpkg-reconfigure -plow unattended-upgrades

# /etc/apt/apt.conf.d/52unattended-upgrades-local
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:30";
Unattended-Upgrade::Mail "ops@example.com";
Unattended-Upgrade::MailReport "on-change";

sudo unattended-upgrade --dry-run --debug
systemctl list-timers 'apt-daily*'
dnf-automatic على RHEL 9 وRocky وAlma
sudo dnf install dnf-automatic

# /etc/dnf/automatic.conf
[commands]
upgrade_type = security
apply_updates = yes
reboot = when-needed

sudo systemctl enable --now dnf-automatic.timer

تخبرك needrestart بالخدمات التي ما زالت تستخدم إصدارات مكتبات قديمة بعد التحديث، ويمكنها إعادة تشغيلها تلقائيًا. وبالنسبة إلى الخوادم التي لا يمكن إعادة تشغيلها كثيرًا، يطبق Ubuntu Pro Livepatch (مجاني لعدد صغير من الأجهزة) وخدمة kpatch المكافئة في RHEL إصلاحات النواة الحرجة في الذاكرة. يقلل هذا إلحاح إعادة التشغيل لكنه لا يلغي الحاجة إليها.

تحصين النواة ومكدس الشبكة

تغلق إعدادات النواة عبر sysctl أساليب الانتحال وإعادة التوجيه وتسريب المعلومات، وتجعل رفع الصلاحيات المحلي أصعب. ضعها في ملف خاص بها حتى لا تستبدلها تحديثات الحزم أبدًا.

/etc/sysctl.d/99-hardening.conf
# Network: anti-spoofing, no redirects, no source routing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_rfc1337 = 1

# Kernel: hide pointers and logs, restrict debugging interfaces
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.unprivileged_bpf_disabled = 1
net.core.bpf_jit_harden = 2
kernel.yama.ptrace_scope = 2
kernel.kexec_load_disabled = 1
kernel.sysrq = 0
kernel.perf_event_paranoid = 3
kernel.randomize_va_space = 2

# File system: block classic /tmp race and link attacks, no setuid core dumps
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
fs.suid_dumpable = 0
التطبيق والتحقق
sudo sysctl --system
sysctl kernel.kptr_restrict net.ipv4.conf.all.rp_filter kernel.yama.ptrace_scope
  • اترك net.ipv4.ip_forward على 0 ما لم يوجه الخادم الحركة. يفعّله Docker وKubernetes وبوابات VPN، وهذا متوقع معها.
  • لا تضبط net.ipv6.conf.all.accept_ra على 0 دون تفكير. فبعض المزودين يضبطون IPv6 عبر إعلانات الموجه، وسيفقد الخادم عنوان IPv6 بعد إعادة التشغيل التالية.
  • يمنع kernel.yama.ptrace_scope = 2 المستخدمين العاديين من ربط أدوات التصحيح بالعمليات. استخدم 1 بدلًا منه إذا كان المطورون يصححون على الجهاز، ولا تستخدم 3 إلا إذا كنت متأكدًا من عدم حاجتك إليه قبل إعادة التشغيل التالية، لأن 3 لا يمكن خفضها أثناء التشغيل.
  • يعمل kernel.kexec_load_disabled في اتجاه واحد حتى إعادة التشغيل، وهذا هو الهدف: لا يستطيع مهاجم يملك root تحميل نواة بديلة.

احظر وحدات النواة الخاصة بأنظمة الملفات وبروتوكولات الشبكة التي لن يستخدمها الخادم أبدًا. فقد وُجدت أخطاء عدة لرفع الصلاحيات المحلي في السنوات الأخيرة في وحدات نادرة الاستخدام تُحمَّل تلقائيًا عند الطلب. يمنع استخدام install مع /bin/false التحميل حتى عند طلب الوحدة صراحة، بينما يوقف blacklist التحميل التلقائي فقط.

/etc/modprobe.d/hardening.conf
install cramfs /bin/false
install freevxfs /bin/false
install hfs /bin/false
install hfsplus /bin/false
install jffs2 /bin/false
install udf /bin/false
install usb-storage /bin/false
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
install firewire-core /bin/false

اربط المجلدات المؤقتة المشتركة بحيث لا يعمل فيها شيء بصلاحية setuid أو كعقدة جهاز. تفشل إضافة noexec إلى /tmp أيضًا كثيرًا من برامج الإسقاط الشائعة، لكن اختبر أولًا، فبعض برامج التثبيت ونصوص الحزم تعمل من /tmp. أما /dev/shm فقفله أكثر أمانًا لأن قليلًا من البرامج المشروعة يعمل منه.

إضافات /etc/fstab وملفات core dump
tmpfs  /dev/shm  tmpfs  defaults,nodev,nosuid,noexec  0 0
tmpfs  /tmp      tmpfs  defaults,nodev,nosuid,size=1G  0 0

sudo systemctl daemon-reload && sudo mount -o remount /dev/shm
findmnt /dev/shm /tmp

# Disable core dumps, which can contain keys and passwords
echo '* hard core 0' | sudo tee /etc/security/limits.d/10-nocore.conf
sudo mkdir -p /etc/systemd/coredump.conf.d
printf '[Coredump]\nStorage=none\nProcessSizeMax=0\n' | sudo tee /etc/systemd/coredump.conf.d/disable.conf

تقليص سطح الهجوم

كل خدمة تستمع شيء يجب تحديثه وشيء يمكن استغلاله. عد إلى مخرجات ss من أول تسجيل دخول وبرر كل سطر. وكل ما يحتاجه الخادم نفسه فقط، مثل قاعدة بيانات أو ذاكرة مؤقتة، يجب أن يستمع على 127.0.0.1 أو مقبس Unix، وليس على 0.0.0.0 أبدًا.

أزل وعطّل ما لا تحتاجه
sudo ss -tulpn
systemctl list-unit-files --type=service --state=enabled
sudo systemctl disable --now avahi-daemon cups rpcbind 2>/dev/null
sudo apt purge -y telnet rsh-client talk xinetd 2>/dev/null

# Bind local services to loopback
#   PostgreSQL  postgresql.conf   listen_addresses = 'localhost'
#   MySQL       mysqld.cnf        bind-address = 127.0.0.1
#   Redis       redis.conf        bind 127.0.0.1 -::1   and   protected-mode yes
#   MongoDB     mongod.conf       net.bindIp: 127.0.0.1
ابحث عن الأذونات الخطرة
# setuid and setgid binaries: compare against a known-good list
sudo find / -xdev \( -perm -4000 -o -perm -2000 \) -type f -printf '%M %u %p\n' 2>/dev/null

# File capabilities, a quieter alternative to setuid
sudo getcap -r / 2>/dev/null

# World-writable directories without the sticky bit, and world-writable files
sudo find / -xdev -type d -perm -0002 ! -perm -1000 2>/dev/null
sudo find / -xdev -type f -perm -0002 ! -path '/proc/*' 2>/dev/null

# Files with no owner, often left behind by removed users or attackers
sudo find / -xdev \( -nouser -o -nogroup \) 2>/dev/null

يستطيع systemd عزل أي خدمة ببضع تعليمات، ويقيّم مدى انكشاف كل وحدة. نفذ systemd-analyze security لرؤية القائمة، ثم أضف ملفًا مستقلًا لخدمات تطبيقاتك. ابدأ بصرامة وخفف إعدادًا واحدًا في كل مرة إذا فشلت الخدمة، وراجع journalctl لمعرفة السبب.

sudo systemctl edit myapp.service
[Service]
User=myapp
Group=myapp
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/myapp /var/log/myapp
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
CapabilityBoundingSet=
AmbientCapabilities=
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
UMask=0077
افحص النتيجة
sudo systemctl daemon-reload && sudo systemctl restart myapp
systemd-analyze security myapp.service       # aim for an exposure score under 3
systemd-analyze security                     # every unit, worst first

أضف MemoryDenyWriteExecute=yes للخدمات المترجمة، لكن لا تضفه إلى Node.js وJava وبيئات التشغيل ذات مترجم JIT، فهي تحتاج إلى ذاكرة قابلة للكتابة والتنفيذ. وإذا كان يجب أن ترتبط الخدمة بالمنفذ 80 أو 443 دون root، فامنحها ذلك تحديدًا عبر AmbientCapabilities=CAP_NET_BIND_SERVICE والقيمة نفسها في CapabilityBoundingSet.

التحكم الإلزامي في الوصول: AppArmor وSELinux

يقيد AppArmor في Ubuntu وDebian، وSELinux في RHEL، العمليات بالملفات والقدرات التي تسمح بها سياساتها، حتى عند تشغيلها بحساب root. ولهذا تبقى اختراقات كثيرة لتطبيقات الويب محصورة في خادم الويب. أبقهما مفعلين في وضع الفرض، فأكثر أخطاء التحصين شيوعًا في RHEL ما زال إيقاف SELinux للتخلص من خطأ.

AppArmor على Ubuntu وDebian
sudo aa-status                               # profiles in enforce and complain mode
sudo apt install apparmor-utils apparmor-profiles apparmor-profiles-extra
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx   # if the profile exists
sudo aa-genprof /usr/local/bin/myapp             # build a profile interactively
sudo aa-logprof                                  # refine it from logged denials
sudo journalctl -k | grep -i apparmor | tail
SELinux على RHEL وRocky وAlma
getenforce && sestatus                       # expect Enforcing, targeted policy
sudo ausearch -m AVC -ts recent | audit2why  # explain recent denials

# Fix the context instead of disabling SELinux
sudo semanage fcontext -a -t httpd_sys_content_t '/srv/www(/.*)?'
sudo restorecon -Rv /srv/www
sudo setsebool -P httpd_can_network_connect on
sudo semanage port -a -t ssh_port_t -p tcp 2222

التسجيل والتدقيق

عند وقوع خلل، تكون الأسئلة نفسها دائمًا: من سجل الدخول، وماذا شغّل، وما الذي تغير. تأكد من أن الخادم يسجل الإجابات، ويحتفظ بها مدة كافية، ويرسل نسخة إلى مكان لا يستطيع مهاجم يملك root تعديله.

journald دائم · /etc/systemd/journald.conf.d/10-persist.conf
[Journal]
Storage=persistent
Compress=yes
SystemMaxUse=2G
MaxRetentionSec=90day

sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
journalctl --disk-usage

يسجل إطار التدقيق في Linux استدعاءات النظام المهمة أمنيًا في النواة، تحت ما يمكن لبرنامج rootkit في مساحة المستخدم إخفاؤه بسهولة. وتمنحك مجموعة قواعد مركزة تغطي ملفات الهوية وإعدادات SSH وsudo والأوامر الامتيازية وتحميل وحدات النواة معظم قيمة التحقيق دون إغراق القرص. وتعد قواعد Florian Roth المجتمعية وأمثلة auditd في CIS Benchmarks نقاط بداية جيدة.

/etc/audit/rules.d/50-hardening.rules
-D
-b 8192
-f 1

# Identity and authentication
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d/ -p wa -k sshd
-w /etc/pam.d/ -p wa -k pam

# Persistence locations
-w /etc/crontab -p wa -k cron
-w /etc/cron.d/ -p wa -k cron
-w /var/spool/cron/ -p wa -k cron
-w /etc/systemd/system/ -p wa -k systemd
-w /etc/ld.so.preload -p wa -k preload

# Commands run as root by a real logged-in user
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=unset -k root_cmd
-a always,exit -F arch=b32 -S execve -F euid=0 -F auid>=1000 -F auid!=unset -k root_cmd

# Kernel modules
-a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k modules

# Make the rules immutable until reboot (keep last)
-e 2
حمّل قواعد التدقيق واستعلم عنها
sudo apt install auditd audispd-plugins     # RHEL: installed by default
sudo augenrules --load
sudo auditctl -s                            # "enabled 2" means locked
sudo auditctl -l

sudo ausearch -k identity -i --start today
sudo ausearch -k root_cmd -i --start recent
sudo aureport --auth --summary
sudo aureport -x --summary                  # most-run executables

لا تكون سجلات الخادم موثوقة إلا حتى يُخترق. أرسلها بشكل شبه فوري إلى SIEM أو خادم سجلات مخصص عبر TLS. يعمل وكيل Wazuh وElastic Agent وSplunk Universal Forwarder وVector جيدًا، ويكفي rsyslog إذا كنت تحتاج إلى نسخة بعيدة فقط.

/etc/rsyslog.d/90-forward.conf · apt install rsyslog-gnutls
global(DefaultNetstreamDriverCAFile="/etc/ssl/certs/log-ca.pem")

action(
  type="omfwd"
  target="logs.example.com" port="6514" protocol="tcp"
  StreamDriver="gtls" StreamDriverMode="1"
  StreamDriverAuthMode="x509/name"
  StreamDriverPermittedPeers="logs.example.com"
  queue.type="LinkedList" queue.filename="fwd" queue.saveOnShutdown="on"
  action.resumeRetryCount="-1"
)

سلامة الملفات وفحص البرمجيات الخبيثة

تجيب مراقبة سلامة الملفات عن السؤال الذي يريد المهاجم ألا تطرحه: ما الذي تغير على القرص؟ تبني AIDE قاعدة بيانات لبصمات ملفات النظام وخصائصها وتبلغ عن الاختلافات. ابنِ القاعدة على نظام سليم، واحتفظ بنسخة خارج الخادم، وشغّل الفحص يوميًا.

AIDE
# Ubuntu and Debian
sudo apt install aide
sudo aideinit
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
sudo aide --check --config /etc/aide/aide.conf

# RHEL, Rocky and Alma
sudo dnf install aide
sudo aide --init
sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
sudo aide --check

# After an intended change such as patching, accept the new state
sudo aide --update --config /etc/aide/aide.conf

يمكن لمديري الحزم أيضًا التحقق من الملفات المثبتة مقارنة ببصماتها، وهي طريقة سريعة لرصد ملف مستبدل مثل sshd أو ps ملغوم. وتضيف أدوات فحص rootkit فحوصًا لملفات rootkit المعروفة والعمليات المخفية ووحدات النواة المشبوهة. وهي تنتج إنذارات خاطئة، فأنشئ خط أساس على نظام سليم وحقق في التغييرات لا في كل تحذير.

التحقق من الحزم وأدوات فحص rootkit
sudo apt install debsums && sudo debsums -s      # changed package files only
sudo rpm -Va | grep -E '^..5'                    # RHEL: files whose hash changed

sudo apt install rkhunter chkrootkit
sudo rkhunter --update && sudo rkhunter --propupd # baseline on a clean system
sudo rkhunter --check --sk --rwo                 # report warnings only
sudo chkrootkit -q

# ClamAV for upload directories and shared storage
sudo apt install clamav && sudo freshclam
clamscan -r -i /srv/uploads

نشر الخدمات بأمان

ينتهي الأمر بمعظم أحمال VPS خلف خادم ويب. أنهِ TLS في وكيل عكسي، وأبقِ خوادم التطبيقات على localhost، وأرسل الترويسات التي تطلب من المتصفحات فرض HTTPS ورفض التضمين في الإطارات وتخمين المحتوى.

أساسيات وكيل Nginx العكسي
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run

# /etc/nginx/conf.d/hardening.conf
server_tokens off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_tickets off;
client_max_body_size 10m;
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;

# inside the server block
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
    limit_req zone=perip burst=20 nodelay;
    proxy_pass http://127.0.0.1:3000;
}

اختبر النتيجة من الخارج باستخدام testssl.sh أو Qualys SSL Labs، ونفذ nginx -t قبل كل إعادة تحميل. أبقِ لوحات الإدارة مثل phpMyAdmin أو Grafana أو واجهة إدارة CMS خارج الاستماع العام تمامًا، وادخل إليها عبر VPN أو نفق SSH.

إذا كنت تستخدم Docker

  • العضوية في مجموعة docker تعادل root على الخادم. لا تمنحها لمن لا تمنحه sudo، ولا تربط أبدًا /var/run/docker.sock بحاوية مكشوفة على الإنترنت.
  • انشر المنافذ على عنوان الحلقة المحلية، مثل 127.0.0.1:8080:8080، واكشف الوكيل العكسي فقط. وتذكر أن المنافذ المنشورة تتجاوز UFW.
  • شغّل الحاويات بمستخدم غير root، ونظام ملفات جذري للقراءة فقط، مع إسقاط كل القدرات وتفعيل no-new-privileges. وأعد فقط ما تحتاجه الصورة.
  • افحص الصور بحثًا عن الثغرات المعروفة في CI وعلى الخادم باستخدام Trivy أو Grype، وأعد البناء بانتظام لتصل إصلاحات الصور الأساسية إلى الإنتاج.
  • فكر في Docker دون root أو Podman لأحمال العمل التي لا تحتاج إلى ميزات امتيازية.
/etc/docker/daemon.json وحاوية محصنة
{
  "icc": false,
  "no-new-privileges": true,
  "live-restore": true,
  "userland-proxy": false,
  "log-driver": "local",
  "log-opts": { "max-size": "20m", "max-file": "5" }
}

docker run -d --name api \
  --user 10001:10001 --read-only --tmpfs /tmp \
  --cap-drop ALL --security-opt no-new-privileges \
  --memory 512m --pids-limit 200 \
  -p 127.0.0.1:8080:8080 registry.example.com/api:1.4.2

trivy image registry.example.com/api:1.4.2

النسخ الاحتياطي وحساب المزود

يقلل التحصين احتمال الاختراق، وتحدد النسخ الاحتياطية مدى سوئه. اتبع قاعدة 3-2-1: ثلاث نسخ، على نوعين من التخزين، إحداها خارج الموقع وبعيدة عن بيانات اعتماد الخادم. لقطة المزود مريحة، لكنها في الحساب نفسه الذي قد يسيطر عليه المهاجم بالفعل.

نسخ احتياطية مشفرة ومزالة التكرار باستخدام restic
sudo apt install restic
export RESTIC_REPOSITORY="s3:https://s3.eu-central-1.amazonaws.com/acme-backups/web-01"
export RESTIC_PASSWORD_FILE=/root/.restic-pass        # chmod 600, also stored in your vault
export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... # a key that can write, not delete

restic init
restic backup /etc /var/lib/myapp /srv --exclude-caches
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
restic check
restic restore latest --target /tmp/restore-test --include /etc/nginx
  • فعّل قفل الكائنات أو الإصدارات في حاوية النسخ الاحتياطي كي لا تحذف الفدية التي تملك بيانات اعتماد الخادم السجل. وشغّل التنظيف من جهاز منفصل وأكثر موثوقية.
  • صدّر قواعد البيانات بأدواتها الأصلية (pg_dump وmysqldump وmongodump) قبل نسخ الملفات، بدل نسخ ملفات البيانات أثناء عملها.
  • اختبر استعادة كاملة إلى VPS جديد مرة كل ربع سنة على الأقل وقس وقتها. هذا الرقم هو وقت تعافيك الحقيقي.
  • احمِ حساب المزود نفسه: MFA بمفتاح عتادي لكل مستخدم، ولا حسابات مشتركة، ورموز API محدودة، وتنبيهات لتسجيلات الدخول إلى اللوحة ومفاتيح API الجديدة. فمن يسيطر على الحساب يستطيع إعادة تعيين root وقراءة الأقراص وحذف اللقطات دون لمس SSH.

التحقق من التحصين

تغيير التحصين الذي لم تختبره أمنية لا ضابط. افحص الخادم من الداخل بأداة تدقيق، ومن الخارج بأداة فحص، ووفق معيار منشور إذا كانت لديك التزامات امتثال.

Lynis: تدقيق محلي مع مؤشر تحصين
sudo apt install lynis            # or clone the latest from GitHub
sudo lynis audit system
sudo grep -E 'warning|suggestion' /var/log/lynis-report.dat | head -50
sudo grep hardening_index /var/log/lynis-report.dat
من الخارج: ماذا يرى الإنترنت؟
nmap -Pn -sS -p- --min-rate 2000 203.0.113.10       # all TCP ports
nmap -Pn -sV -sC -p 22,80,443 203.0.113.10            # versions and default scripts
nmap -Pn -sU --top-ports 50 203.0.113.10              # common UDP services
nmap -6 -Pn -sS -p- 2001:db8::10                      # do not forget IPv6
testssl.sh https://example.com
ssh-audit 203.0.113.10
فحوص CIS Benchmarks
# RHEL, Rocky and Alma: OpenSCAP with the SCAP Security Guide
sudo dnf install openscap-scanner scap-security-guide
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --results /root/cis-results.xml --report /root/cis-report.html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

# Ubuntu Pro: the Ubuntu Security Guide
sudo pro enable usg && sudo apt install usg
sudo usg audit cis_level1_server

لا تطبق ملف CIS كاملًا مع معالجة تلقائية على خادم إنتاج عامل دون اختباره أولًا على نسخة. فالمعايير مكتوبة لجهاز عام، وبعض الضوابط ستعطل شيئًا يعتمد عليه عملك. سجل كل استثناء وسببه، فهذا تحديدًا ما سيطلبه المدقق.

حافظ على التحصين

تنحرف الخوادم بمرور الوقت. تضيف الحزم خدمات، ويفتح الزملاء منافذ لاختبار سريع، وتبقى مفاتيح الموظفين السابقين في authorized_keys لسنوات. جدول الفحوص، وإن أمكن اكتب الإعداد كله في Ansible أو cloud-init أو أداة إدارة إعدادات أخرى، ليعود الخادم المعاد بناؤه محصنًا افتراضيًا.

جدول صيانة التحصين
التكرارالمهمةالطريقة
يوميًاتثبيت التحديثات الأمنيةunattended-upgrades أو dnf-automatic، مع بريد عند التغيير
يوميًامراجعة السلامة والسجلاتفحص AIDE وملخص Fail2ban أو CrowdSec وتنبيهات SIEM
أسبوعيًاإعادات التشغيل المعلقةملف reboot-required وneedrestart وneeds-restarting
شهريًاالانكشاف الخارجيnmap لكل العناوين وtestssl.sh وssh-audit
شهريًامراجعة الوصولالمستخدمون وsudoers وauthorized_keys وأعضاء حساب المزود
ربع سنويالمعيار واختبار الاستعادةتقرير Lynis أو OpenSCAP واستعادة كاملة إلى VPS جديد
سنويًاتدوير المفاتيح والأسرارمفاتيح SSH ورموز API وبيانات اعتماد النسخ الاحتياطي ومفاتيح TLS

قائمة التحقق من التحصين

  1. أخذ لقطة، وتحديث النظام بالكامل، وضبط اسم الجهاز، والساعة على UTC ومتزامنة.
  2. حسابات مسؤولين بأسماء محددة مع sudo، وكلمة مرور root مقفلة، وتفعيل سجلات sudo وuse_pty.
  3. يقبل SSH المفاتيح فقط، دون دخول root، ومقيد بمجموعة مسموح بها، بخوارزميات حديثة، وتم التحقق منه عبر ssh-audit.
  4. يمنع جدار حماية الخادم الدخول افتراضيًا على IPv4 وIPv6، مع جدار حماية المزود في المقدمة.
  5. Fail2ban أو CrowdSec يعمل ويحظر.
  6. تحديثات أمنية تلقائية مع إعادة تشغيل مجدولة، وتثبيت needrestart.
  7. تطبيق تحصين sysctl، وحظر وحدات النواة غير المستخدمة، وربط /dev/shm و/tmp مع nosuid وnodev.
  8. تبرير كل منفذ يستمع، وربط الخدمات المحلية بالحلقة المحلية، ومراجعة ملفات setuid.
  9. عزل خدمات التطبيقات بتعليمات systemd وتشغيلها بمستخدميها الخاصين.
  10. AppArmor أو SELinux في وضع الفرض.
  11. journald دائم، وقواعد auditd محملة ومقفلة، وإرسال السجلات خارج الخادم عبر TLS.
  12. خط أساس AIDE مخزن خارج الخادم ومفحوص يوميًا.
  13. إنهاء TLS في وكيل عكسي مع ترويسات أمنية، ولوحات الإدارة متاحة عبر VPN فقط.
  14. نسخ احتياطية مشفرة خارج الموقع مع حماية من الحذف واستعادة مختبرة.
  15. حساب المزود محمي بـ MFA بمفتاح عتادي وتنبيهات.

الخاتمة

تزيل هذه الخطوات أسهل الطرق إلى الخادم: تسجيل الدخول بكلمة المرور، والخدمات المكشوفة، والبرمجيات غير المحدثة، والسجلات الناقصة. ولا يفيد التحصين إلا إذا بقي قائمًا، لذا أعد خطوات التحقق بعد كل تغيير كبير وراجع القائمة بانتظام.

  • Linux
  • التحصين
  • VPS
  • SSH
  • جدار الحماية
  • nftables
  • auditd
  • SELinux
  • AppArmor
  • CIS Benchmark
  • القيادة الأمنيةقراءة 24 دقيقة

    ستتعرض للاختراق. مهمتك أن تجعل ذلك مكلفًا.

    لا وجود للأمن الكامل، والذكاء الاصطناعي يخفض تكلفة الهجوم. دليل لمسؤولي أمن المعلومات عن مستويات التهديد، والدفاع بالذكاء الاصطناعي، والحوار مع مجلس الإدارة، ورفع ثمن اختراقك.

  • الاستجابة للحوادثقراءة 14 دقيقة

    كيف تستجيب لهجوم فدية: دليل خطوة بخطوة

    ما يجب فعله في الساعة الأولى من هجوم الفدية وما بعدها: الاحتواء والأدلة وتحديد النطاق وسرقة البيانات وقرار الدفع والإبلاغ والإزالة وترتيب التعافي والتحصين، مع الأوامر.

  • الاستجابة للحوادثقراءة 23 دقيقة

    الفرز الجنائي في Windows للاستجابة للحوادث

    دليل عملي لفرز أجهزة Windows المخترقة: التقاط الذاكرة، والاستجابة المباشرة، والبحث عن وسائل الاستمرار، وسجلات الأحداث، وآثار التنفيذ، والجمع عبر KAPE وVelociraptor.

  • الاستجابة للحوادثقراءة 21 دقيقة

    الفرز الجنائي في Linux للاستجابة للحوادث

    دليل عملي لفرز خوادم Linux والحاويات المخترقة: التقاط الذاكرة، وتحليل /proc، ومفاتيح SSH، والسجلات، والبحث عن وسائل الاستمرار، وفحص rootkit، والجمع عبر UAC.

تحصين خادم Linux VPS: دليل عملي كامل | ABYSSS