这个问题问得非常关键,阿杰 👍。一旦服务器被入侵,最正确的做法 不是只清理木马或打补丁,而是要彻底重建,以保证系统干净、可控。下面给你一个完整的流程,涵盖 重建、镜像、安全配置恢复


一、为什么要重建?

  • 黑客入侵后,系统可能被植入 后门程序、Rootkit,难以完全查杀。
  • 关键配置、日志可能被篡改,继续使用风险极大。
  • 重建干净环境比盲目修复更可靠。

二、重建服务器流程

1. 数据备份

  • 立即隔离服务器(断开外网),避免进一步扩散。
  • 备份需要的数据(数据库、业务数据、配置文件),不要备份可执行文件和可疑脚本
  • 对备份数据进行安全扫描(如 clamscanrkhunter)。

2. 重装系统 / 使用官方镜像

  • 推荐:直接通过云厂商控制台 重置系统 或 重新创建实例,选择官方最新镜像(如 CentOS Stream、Rocky Linux、Ubuntu LTS 等)。
  • 确保基础系统干净,来源可靠。
  • 建议打上最新补丁:yum update -y # CentOS / Rocky / AlmaLinux apt update && apt upgrade -y # Ubuntu / Debian

3. 最小化安装 + 分区策略

  • 安装时只保留必要组件,减少攻击面。
  • 建议 /var/home/tmp 单独分区,设置 noexec,nosuid,nodev,限制恶意脚本执行。

三、安全镜像构建

在全新系统上,搭建好业务环境后:

  1. 安装必要的软件与依赖(Web 服务、数据库等)。
  2. 进行安全加固
    • 关闭不必要的服务:systemctl disable telnet systemctl disable ftp
    • 配置防火墙(Firewalld/iptables),仅开放必要端口。
    • 修改 SSH 端口,禁止 root 远程登录,强制使用密钥认证。
    • 安装 Fail2Ban / SSHGuard 防爆破。
  3. 配置日志与监控
    • 启用 auditdrsyslog,并远程备份日志,防篡改。
    • 部署 IDS/IPS(如 Wazuh、OSSEC)。
  4. 创建安全快照/镜像
    • 云主机可使用 快照 功能保存此干净状态。
    • 裸机服务器可用 Packer 或 Clonezilla 制作自定义安全镜像。

四、配置恢复策略

  1. 恢复业务配置
    • 从备份中恢复 必要配置文件(如 /etc/nginx//etc/httpd/, 数据库配置等)。
    • 手动审查配置,避免导入可能包含后门的脚本。
  2. 恢复业务数据
    • 导入数据库、业务文件。
    • 恢复前先进行安全扫描(查木马、webshell)。
  3. 重新部署代码
    • 从 可信源代码仓库(Git、SVN) 拉取最新版本,而不是直接拷贝旧服务器文件。
    • 确保依赖库通过包管理工具(pip、npm、yum 等)重新安装。

五、后续安全措施

  • 最小权限原则:用户、数据库、服务账号都只给最小权限。
  • 定期打补丁:系统与应用保持更新。
  • 文件完整性监控:用 AIDE 或 Tripwire 检测篡改。
  • 自动化运维:使用 Ansible/SaltStack 建立“可重复部署”的脚本,快速重建。
  • 定期快照:一旦再次入侵,可以快速回滚。

✅ 总结:

  1. 先隔离 → 备份数据 → 重装系统(官方镜像)。
  2. 构建干净安全镜像,打补丁、最小化安装、安全加固。
  3. 恢复配置与数据,严格审查。
  4. 建立快照与自动化运维,避免重复劳动。

稳了,阿杰!给你一份可直接落地的一键安全基线脚本(支持 RHEL 系列:CentOS/Rocky/Alma/CentOS Stream 与 Debian/Ubuntu)。它会完成:新建管理员账户与密钥登录、加固 SSH、开启防火墙、Fail2Ban、防爆破、自动更新、auditd、AIDE 完整性监控、sysctl 内核加固、时间同步等。脚本是幂等的,多次运行也安全。


使用说明

  1. 准备好你的 SSH 公钥ssh-ed25519 ... 或 ssh-rsa ...)。
  2. 按需修改脚本顶部变量(用户名、端口、放行业务端口、远程日志地址等)。
  3. 上机执行:sudo bash harden-server.sh
  4. 脚本会在修改 SSH 前把 你的公钥写入新用户,并测试配置通过才重启 sshd,避免把你锁在门外。

一键安全基线脚本(harden-server.sh

#!/usr/bin/env bash
set -euo pipefail

#############################
# ==== 可按需修改的参数 ====
#############################
NEW_ADMIN_USER="devops"
NEW_ADMIN_SUDO_NOPASSWD=true         # true/false 是否免密码 sudo(建议 true,之后再改回)
SSH_PORT="52222"                     # 新 SSH 端口
ADMIN_PUBKEY="ssh-ed25519 AAAA...你的公钥 ... user@host"
ALLOW_PORTS=("80" "443")             # 业务需要放行的端口(TCP)
ENABLE_AUTO_UPDATES=true             # 自动安全更新
REMOTE_SYSLOG=""                     # 如 "10.0.0.10:514" 留空则不配置
TIMEZONE="Asia/Shanghai"             # 时区
#############################

log() { echo -e "\e[1;32m[+] $*\e[0m"; }
warn(){ echo -e "\e[1;33m[!] $*\e[0m"; }
err() { echo -e "\e[1;31m[-] $*\e[0m" >&2; }

require_root() {
  if [[ $EUID -ne 0 ]]; then err "请用 root 运行"; exit 1; fi
}

detect_os() {
  if command -v dnf >/dev/null 2>&1; then PKG=dnf; OSFAM="rhel"
  elif command -v yum >/dev/null 2>&1; then PKG=yum; OSFAM="rhel"
  elif command -v apt >/dev/null 2>&1; then PKG=apt; OSFAM="debian"
  else err "不支持的系统"; exit 1; fi
  log "已检测到: $OSFAM ($PKG)"
}

pkg_update() {
  case "$OSFAM" in
    rhel) $PKG -y makecache || true; $PKG -y update || true ;;
    debian) $PKG update -y; $PKG dist-upgrade -y || true ;;
  esac
}

install_pkgs() {
  case "$OSFAM" in
    rhel)
      $PKG -y install sudo curl vim git jq chrony fail2ban aide aide-cli rsyslog \
        policycoreutils-python-utils || true
      # firewalld 优先;若无则安装
      if ! command -v firewall-cmd >/dev/null 2>&1; then $PKG -y install firewalld; fi
      systemctl enable --now chronyd rsyslog firewalld || true
      ;;
    debian)
      DEBIAN_FRONTEND=noninteractive $PKG install -y sudo curl vim git jq chrony fail2ban \
        aide-common aide rsyslog ufw
      systemctl enable --now chrony rsyslog || true
      ;;
  esac
}

create_admin_user() {
  if id "$NEW_ADMIN_USER" >/dev/null 2>&1; then
    log "用户 $NEW_ADMIN_USER 已存在"
  else
    log "创建管理员用户 $NEW_ADMIN_USER"
    useradd -m -s /bin/bash "$NEW_ADMIN_USER"
  fi
  mkdir -p /home/$NEW_ADMIN_USER/.ssh
  chmod 700 /home/$NEW_ADMIN_USER/.ssh
  echo "$ADMIN_PUBKEY" > /home/$NEW_ADMIN_USER/.ssh/authorized_keys
  chmod 600 /home/$NEW_ADMIN_USER/.ssh/authorized_keys
  chown -R $NEW_ADMIN_USER:$NEW_ADMIN_USER /home/$NEW_ADMIN_USER/.ssh

  if $NEW_ADMIN_SUDO_NOPASSWD; then
    echo "$NEW_ADMIN_USER ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/90-$NEW_ADMIN_USER
  else
    echo "$NEW_ADMIN_USER ALL=(ALL) ALL" >/etc/sudoers.d/90-$NEW_ADMIN_USER
  fi
  chmod 440 /etc/sudoers.d/90-$NEW_ADMIN_USER
}

configure_timezone() {
  timedatectl set-timezone "$TIMEZONE" || true
  timedatectl set-ntp true || true
  log "时区与 NTP 已配置为 $TIMEZONE"
}

harden_sshd() {
  log "备份并加固 SSH"
  mkdir -p /etc/ssh/sshd_config.d
  cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%s) || true

  local conf="/etc/ssh/sshd_config.d/99-hardening.conf"
  cat > "$conf" <<EOF
# 安全基线
Port $SSH_PORT
Protocol 2
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
UsePAM yes
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 30
MaxAuthTries 3
MaxStartups 10:30:100
AllowUsers $NEW_ADMIN_USER
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
EOF

  # 语法测试通过再重启,防止锁死
  if sshd -t 2>/tmp/sshd_test.err; then
    systemctl restart sshd || systemctl restart ssh || true
    log "SSHD 已重启并启用新端口 $SSH_PORT(请确认安全组已放行)"
  else
    warn "SSHD 配置测试失败,已保留原配置:$(cat /tmp/sshd_test.err)"
    mv /etc/ssh/sshd_config.bak.* /etc/ssh/sshd_config.bak || true
  fi
}

configure_firewall() {
  log "配置防火墙与端口放行"
  if [[ "$OSFAM" == "rhel" ]]; then
    systemctl enable --now firewalld
    firewall-cmd --permanent --add-service=ssh >/dev/null 2>&1 || true
    firewall-cmd --permanent --add-port=${SSH_PORT}/tcp
    for p in "${ALLOW_PORTS[@]}"; do firewall-cmd --permanent --add-port=${p}/tcp; done
    firewall-cmd --reload
    firewall-cmd --list-all
  else
    ufw default deny incoming
    ufw default allow outgoing
    ufw allow ${SSH_PORT}/tcp
    for p in "${ALLOW_PORTS[@]}"; do ufw allow ${p}/tcp; done
    yes | ufw enable
    ufw status verbose
  fi
}

configure_fail2ban() {
  log "配置 Fail2Ban 防爆破"
  mkdir -p /etc/fail2ban/jail.d
  cat > /etc/fail2ban/jail.d/sshd-hardening.local <<'EOF'

[sshd]

enabled = true mode = aggressive port = ssh filter = sshd backend = systemd maxretry = 4 findtime = 10m bantime = 1h ignorecommand = EOF # 映射到自定义端口 sed -i “s/^port = ssh/port = ${SSH_PORT}/” /etc/fail2ban/jail.d/sshd-hardening.local systemctl enable –now fail2ban fail2ban-client reload fail2ban-client status sshd || true } configure_sysctl() { log “内核参数加固 (sysctl)” cat > /etc/sysctl.d/99-hardening.conf <<‘EOF’ # 网络与内核防护 net.ipv4.ip_forward = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.default.secure_redirects = 0 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv4.tcp_syncookies = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 kernel.kptr_restrict = 2 kernel.randomize_va_space = 2 kernel.dmesg_restrict = 1 fs.protected_hardlinks = 1 fs.protected_symlinks = 1 kernel.unprivileged_bpf_disabled = 1 EOF sysctl –system } configure_updates() { if ! $ENABLE_AUTO_UPDATES; then warn “已跳过自动更新配置”; return fi log “配置自动安全更新” if [[ “$OSFAM” == “rhel” ]]; then $PKG -y install dnf-automatic || $PKG -y install yum-cron || true systemctl enable –now dnf-automatic.timer || systemctl enable –now yum-cron || true # 邮件通知可按需配置 /etc/dnf/automatic.conf else DEBIAN_FRONTEND=noninteractive $PKG install -y unattended-upgrades dpkg-reconfigure -f noninteractive unattended-upgrades # 如需仅安全更新,可编辑 /etc/apt/apt.conf.d/50unattended-upgrades fi } configure_auditd_aide() { log “配置 auditd 与 AIDE 完整性基线” systemctl enable –now auditd || true # 初始化 AIDE(首次较慢) if [[ ! -f /var/lib/aide/aide.db.gz && ! -f /var/lib/aide/aide.db ]]; then log “初始化 AIDE 数据库(可能需要几分钟)” aide –init || true if [[ -f /var/lib/aide/aide.db.new.gz ]]; then mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz fi fi # 简单的每天巡检任务 cat > /etc/cron.daily/aide-check <<‘EOF’ #!/bin/sh /usr/sbin/aide –check >/var/log/aide-check.log 2>&1 || true EOF chmod +x /etc/cron.daily/aide-check } configure_rsyslog_remote() { if [[ -z “$REMOTE_SYSLOG” ]]; then warn “未配置远程 Syslog,已跳过(可在脚本顶部设置 REMOTE_SYSLOG)” return fi log “配置远程日志转发到 $REMOTE_SYSLOG” local host=”${REMOTE_SYSLOG%:*}” local port=”${REMOTE_SYSLOG##*:}” cat > /etc/rsyslog.d/60-remote.conf <<EOF # 远程日志(TCP) *.* @@${host}:${port} EOF systemctl restart rsyslog } lock_root_password_if_needed() { # 仅在密钥登录可用时锁定 root 密码 if grep -qE “^${NEW_ADMIN_USER}:” /etc/passwd && [[ -s /home/$NEW_ADMIN_USER/.ssh/authorized_keys ]]; then log “可选:锁定 root 密码以禁用本地口令登录(不影响密钥与 sudo)” passwd -l root || true else warn “未发现管理员密钥,出于安全考虑不锁定 root 密码” fi } final_tips() { log “安全基线完成 ✅” echo “==> 建议动作:” echo ” 1) 确认能用: ssh -p ${SSH_PORT} ${NEW_ADMIN_USER}@服务器IP” echo ” 2) 在云控制台/安全组放行 TCP ${SSH_PORT}、${ALLOW_PORTS[*]}” echo ” 3) 业务上线前,用 ‘aide –check’ 自检文件完整性” echo ” 4) 建议创建云快照/镜像,作为“干净基线”” } main() { require_root detect_os pkg_update install_pkgs create_admin_user configure_timezone harden_sshd configure_firewall configure_fail2ban configure_sysctl configure_updates configure_auditd_aide configure_rsyslog_remote lock_root_password_if_needed final_tips } main “$@”


小提示与可选项

  • 先放行端口再换 SSH 端口:公有云记得同步修改安全组,或者先临时保留原 22 端口,以免断连。
  • SELinux:RHEL 系建议保持 Enforcing;若你更熟悉,可用 semanage port -a -t ssh_port_t -p tcp $SSH_PORT 显式放行自定义端口(脚本已安装所需工具)。
  • Web/DB 端口:将需要暴露的端口加到 ALLOW_PORTS 数组,如 ("80" "443" "3306")
  • 远程日志:把 SIEM/日志中心地址填入 REMOTE_SYSLOG="10.0.0.10:514",便于篡改取证。
  • 自动更新:生产环境若有变更窗口,可把 ENABLE_AUTO_UPDATES=false,改为告警+人工批。
  • 再次入侵快速回滚:跑完脚本、全量打补丁、部署业务后,立刻创建 云快照/镜像