云服务器安全基线:上线前必须做的 9 项加固清单

云服务器安全基线:上线前必做的 9 项加固清单,从 SSH 密钥登录、安全组最小权限,到 MFA、补丁节奏与恢复演练,附可直接复制的命令。

2026-09-18

云服务器安全基线:上线前必做的 9 项加固清单,从 SSH 密钥登录、安全组最小权限,到 MFA、补丁节奏与恢复演练,附可直接复制的命令。

一台云服务器被攻破的路径通常很朴素:扫到开放的 22 端口 → 爆破出弱口令或撞库成功 → 拿到 root → 植入计划任务、挖矿或横向移动。云服务器安全基线要做的,就是把这条链上的每一环都变贵:让扫到无意义、让爆破无入口、让 root 拿不到、让操作留得下痕迹。

判断标准不是「做没做」,而是「能不能被别人验证」。 每项加固都要配一条你自己能跑的验证命令——基线不是一份文档,而是每月能重新跑一遍的检查。

上线前 9 项加固总览(可直接当 checklist)

这 9 项拆开看,本质是三件事:减少入口(SSH、防火墙)、减少权限(非 root、MFA、最小授权)、保证出事能兜住(备份、日志、凭证轮换)。下表是最低标准,不是目标值——先做到,再谈更严格。需要托管侧能力(WAF、DDoS 高防、堡垒机)时,对照 云安全产品 补齐。

#加固项上线前最低标准怎么验证
1SSH 登录禁止 root 与密码登录,仅密钥sshd -T 中两项均为 no
2防火墙 / 安全组管理端口只对来源 IP 开放安全组无 0.0.0.0/0 的 22/3306/6379
3账号与权限一人一个 IAM 身份,不共享 root 密钥IAM 用户可逐人对应到人
4MFA主账号与高权限子账号强制开启控制台显示已启用
5补丁系统每月,业务依赖每季度apt list --upgradable 无积压
6备份与恢复每日自动快照 + 季度恢复演练从快照拉起新实例成功一次
7加密磁盘静态加密 + 全站 TLS 1.2+curl -I https:// 返回 200
8日志与告警留存 ≥ 90 天,新 SSH key 告警lastb -ai 有记录且可查
9密钥管理凭证不入库,托管并可轮换仓库扫描无高熵串命中

顺序有讲究:先 SSH 密钥登录,再动防火墙。 反过来做(先关端口再推 key)会把自己锁在门外,只能走云厂商的救援模式,而那通常需要人工工单。

加固 1|SSH:关掉密码登录,只留密钥

暴力破解 SSH 至今仍是云主机被入侵的第一入口。第一项加固就是:让「密码」这条路径根本不存在。

  1. 给自己或 deploy 用户生成新密钥:ssh-keygen -t ed25519 -C "you@laptop",再把公钥推上去:cat ~/.ssh/id_ed25519.pub | ssh deploy@SERVER "umask 077; mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
  2. 在新开的终端里实测能登录,确认成功后再动配置。原来的会话先别关。
  3. 备份配置:sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak。注意 sshd 多数配置项是首次出现生效,所以要改现有行,往文件末尾追加是无效的。
  4. 禁 root 登录:sudo sed -i "s/^#*PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config
  5. 禁密码登录:sudo sed -i "s/^#*PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config。旧发行版里这一项叫 ChallengeResponseAuthentication,同样要处理。
  6. 先验语法再重载:sudo sshd -t && sudo systemctl reload ssh(RHEL 系服务名为 sshd)。
  7. 确认生效值:sudo sshd -T | grep -Ei "permitrootlogin|passwordauthentication",应输出 PermitRootLogin no 与 PasswordAuthentication no。

再叠一层 fail2ban 限制尝试频率:sudo apt install -y fail2ban && sudo systemctl enable --now fail2ban,用 sudo fail2ban-client status sshd 看已封禁的 IP。

关于「把 22 改成 2222」:这不会让你更安全。公开扫描工具 1–65535 全扫,改端口只是让默认日志安静一点;真正的收益来自来源限制与密钥登录。

加固 2|防火墙与安全组:默认拒绝,按需开口

网络层的目标是默认拒绝。云厂商的安全组是第一道墙(流量到达主机前就被丢弃),主机内的 ufw / firewalld 是第二道墙。两道墙都留着,成本几乎为零。

  • 安全组:只把 80/443 放给 0.0.0.0/0;22 只放给办公网出口 IP;3306 / 5432 / 6379 / 27017 / 9200 一律不给 0.0.0.0/0
  • Debian/Ubuntu 主机防火墙:sudo ufw default deny incoming → sudo ufw allow 22/tcp → sudo ufw allow 80,443/tcp → sudo ufw enable
  • RHEL 系主机防火墙:sudo firewall-cmd --permanent --add-service=http --add-service=https,再用 --add-rich-rule 只对指定来源放行 22,最后 sudo firewall-cmd --reload
  • 数据库只监听回环或内网:MySQL 配 bind-address=127.0.0.1;Redis 配 bind 127.0.0.1 -::1 并保持 protected-mode yes,远程访问走 VPC 私网 + 安全组

ufw enable 之前必须先 ufw allow 22/tcp(Ubuntu 上 ufw allow OpenSSH 也可以,它是同名别名规则)。顺序反了会立刻断开当前 SSH 会话。

自查两处:本机看监听端口 ss -tulpn | grep LISTEN,从另一台机器看对外暴露 nmap -Pn your.server.ip。两处结果都只应有你打算开放的端口。

加固 3|账号:一个人一个身份,不共享 root

把 root 当成「系统自己的账号」,人一律不直接用。目标状态是:每个人的操作都能追溯到一个具体身份,出事能单独吊销而不影响同事。

  1. 云控制台侧:新建 IAM 子账号(RAM 子用户同理),按最小权限给策略,只授予「只读监控」或「只能操作这台实例」这类范围;删掉主账号的长期 AccessKey,CI 与运维改用角色 + 临时凭证,有效期设 15–60 分钟
  2. 主机侧:建 deploy 用户做日常运维,用 sudo visudo 只授权必要命令,而不是整条 NOPASSWD: ALL
  3. 一人一把 SSH 密钥,不要把同一个 id_rsa 复制给全组。人员变动时删一行 authorized_keys 即可精确吊销
  4. 给私钥加口令并用 ssh-agent 缓存:ssh-keygen -p -f ~/.ssh/id_ed25519 + eval "$(ssh-agent -s)",兼顾安全与体验

精确授权的写法(追加到 /etc/sudoers.d/deploy):deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp.service。只放开真正要用的那一条命令,而不是整台机器的 root。

加固 4|MFA:给「删库」动作加一道真实校验

密钥和密码都可能被复制、被钓走,MFA 是唯一能推翻「凭证已泄露就直接可用」这个假设的机制。它不防入侵,防的是凭证已经泄露的情况。

  • 主账号必须开 MFA,且不要只依赖短信:SIM 补卡、短信轰炸都是常见手法,优先 TOTP(Google Authenticator、1Password、Bitwarden 等)
  • 按权限分级强制:能改安全组、能删资源的子账号必须开,纯只读账号可以暂不强制
  • 恢复码离线保存:放密码管理器或打印密封,不放在同一台机器上,也不要发到工作群里
  • 控制台登录与 SSH 登录是两件事:前者用控制台 MFA,后者需要在 PAM 里接 pam_google_authenticator,或用 sshd 的 AuthenticationMethods 组合策略

别把 MFA 做成「形同虚设」:团队里必须有人能走流程帮同事重置,而这个人自己也要开 MFA。否则一次误操作就会变成一场线上求助。

云侧可以用策略强制,而不是口头要求:在权限策略的 Condition 里加 "Bool": { "aws:MultiFactorAuthPresent": "true" },未开启 MFA 的调用直接被拒。

加固 5|补丁:把更新变成日程,而不是事故

加固不是一次性动作。原则很简单:能修的当天修,修不了的(要发版、要重启)排进固定窗口。

  1. 系统层:Debian/Ubuntu 用 sudo apt update && sudo apt list --upgradable 查看,装 unattended-upgrades 并在 /etc/apt/apt.conf.d/20auto-upgrades 里设 APT::Periodic::Update-Package-Lists "1"; 与 APT::Periodic::Unattended-Upgrade "1";
  2. RHEL 系:手动用 dnf update -y,自动化交给 dnf-automatic:sudo systemctl enable --now dnf-automatic.timer
  3. 内核与应用依赖:内核升级要重启才生效(uname -r 确认版本,固定窗口执行 sudo reboot);依赖单独扫:npm audit --production、pip-audit、govulncheck ./...
  4. 容器镜像:定期 docker build --pull 重建,基础镜像的漏洞不会因为你的业务代码没改就消失

发行版有生命周期上限:主流发行版的标准维护窗口通常约 5 年,之后不再有安全更新(CentOS 7 已于 2024 年 6 月结束,Ubuntu 20.04 LTS 标准维护已于 2025 年 5 月结束)。仍在跑的机器要么升版本,要么确认已接入商业延保。

想要一次性全量体检:sudo apt install -y lynis && sudo lynis audit system,把报告存档作为合规证据,也方便对比下一次的变化。

加固 6|备份:有快照不算数,恢复成功才算

备份的价值不在「有」,在「能恢复」。没演练过的备份只是一个假设。

  • 自动快照:每日 1–2 次,保留 7–14 天;每次发版或改数据库结构前手动打一次快照并打标签注明变更
  • 快照不等于应用一致性备份:进程写到一半被快照,恢复后 InnoDB 会自行回滚,但逻辑上可能丢事务。数据库额外做导出:mysqldump --single-transaction --quick -u root -p dbname > /backup/db-$(date +%F).sql.gz(InnoDB 用 --single-transaction 代替 --lock-tables)
  • 异地留一份:快照跨区域复制,或同步到对象存储,并且给备份本身加密——备份文件常含全量用户数据,是最容易被忽略的泄露源
  • 恢复演练:每季度从快照拉一台新实例(隔离网络),核对数据条数与最新时间戳,记录真实 RTO,然后销毁测试实例

演练结果才写进 runbook。写「RTO 2 小时」不如写「2026 年 8 月实测:从快照到数据可读 38 分钟」——后者是数字,前者是承诺。

加固 7|加密:磁盘静态加密 + 全链路 TLS

加密的目标很具体:磁盘被人拿走、备份被下载、流量被中间人读取时,数据依然不可读。

  • 静态加密:云硬盘与快照通常默认启用厂商侧静态加密(一般不额外计费);备份桶、对象存储、数据库快照建议启用客户管理密钥(CMK),这样人员离职时可以连密钥一起吊销。CMK 一般按密钥数量与调用次数计费,以云厂商官网实时报价为准
  • 传输加密:全站 HTTPS,Nginx 只保留 ssl_protocols TLSv1.2 TLSv1.3;,80 全量跳 443 并配置 HSTS;证书用 sudo certbot --nginx -d example.com 自动续期
  • 内部链路也加密:同 VPC 内多机互访走私网 IP,数据库连接强制 TLS 并校验证书,Redis / MySQL 端口不对外暴露
  • SSH 细节:ForwardAgent no,关闭不必要的端口转发;团队用 ssh-agent 统一管理私钥,而不是散落在多台机器上

传输加密不只影响前台 API。上传接口、webhook 回调、对象存储的预签名 URL、第三方 SDK 的证书校验开关都要确认没有被关掉——这类问题在测试环境常常是默认开启的。

证书过期引发的事故,根因通常不是加密机制有问题,而是没人管续期。把续期做成自动化,而不是靠人记得。

加固 8|日志与告警:留痕 90 天,新钥匙要报警

出事时的分水岭只有一个问题:三天前发生过什么,现在能不能查到。

  1. 系统日志留存:/etc/logrotate.d/rsyslog 里设 rotate 14 + daily,并用 journalctl --disk-usage 确认落盘量在可控范围内
  2. 开 auditd 记录敏感文件变更:sudo systemctl enable --now auditd,规则写进 /etc/audit/rules.d/audit.rules:
  • 规则行:-w /etc/passwd -p wa -k identity、-w /etc/sudoers -p wa -k sudo、-w /etc/ssh/sshd_config -p wa -k sshd_config
  • 加载生效:sudo augenrules --load(RHEL 系还要 sudo systemctl restart auditd)
  • 事后查询:sudo ausearch -k identity -ts recent
  1. 云侧审计:开启对象存储访问日志与云厂商的操作审计服务(CloudTrail / 操作审计一类),日志桶用独立账号写入并开启保留策略
  2. 告警只留三条高信号:新增 SSH 公钥、失败登录突增(陌生 IP 段爆破)、非工作时间的管理操作

留存周期给个下限:在线 30–90 天,导出到对象存储再存一年。登录记录用 last -ai(成功)与 lastb -ai(失败)快速排查。

fail2ban 的默认阈值容易在网络抖动时误封整段办公室出口 IP。配置后先用 sudo fail2ban-client status sshd 观察一周,再收紧封禁时长。

加固 9|密钥管理:任何凭证都不进代码仓库

凭证泄露最常见的路径不是被黑客攻破,而是被提交进 git、被写进镜像层、被贴进工单和聊天记录。

  1. 代码里不写密钥:.env 进 .gitignore;已经提交过就按已泄露处理——git rm --cached .env 只能停止后续跟踪,历史里的必须用 git filter-repo 改写,并且同时轮换那把凭证
  2. 提交前自动扫描:gitleaks detect 或 trufflehog git .,挂到 pre-commit 或 CI 上
  3. 运行时注入:由 CI/CD 注入环境变量,或放云厂商的密钥管理服务(Secrets Manager / KMS 一类),应用启动时拉取并缓存;不要写进 Dockerfile 的 ENV,那等于打进镜像
  4. 文件权限:chmod 600 .env,用 umask 077 创建敏感文件,应用以独立系统用户运行,必要时 chown root:appgroup 后 chmod 640

命令行参数会出现在 ps 输出里:mysql -uroot -pPASSWORD 这种写法,同机器任何用户 ps aux 就能看到密码。改用交互提示符,或 mysql --defaults-extra-file=/root/.my.cnf。同理检查 shell history 里有没有 export SECRET=...。

轮换要有节奏:数据库密码 ALTER USER 与应用同步更新,第三方 API key 按季度轮换,并给每把凭证登记用途、负责人、创建时间与失效日期——没有到期日的密钥,迟早会变成永久密钥。

密钥泄露了怎么办:15 分钟应急清单

假设一把 SSH 私钥或一个云 AccessKey 泄露了。第一个动作是吊销,不是改密码,也不是先观察两天。

  1. 吊销(0–5 分钟):在 IAM 控制台禁用或删除泄露的 AccessKey;SSH 侧从所有服务器的 authorized_keys 移除对应公钥(先确认你还有别的入口,否则会把自己关在门外)
  2. 留证(5–15 分钟):立刻给受影响实例打快照并导出证据——sudo last -ai、lastb -ai、sudo journalctl -u ssh --since "-24h"、当前 ss -tulpn 结果、计划任务与自定义 systemd 单元(/etc/cron*、/etc/systemd/system/)
  3. 排查(15–60 分钟):新增系统用户、authorized_keys 差异、crontab -l、异常监听端口、异常出站连接(ss -tunp)、可疑的公钥注释名
  4. 轮换(同步进行):从这台机器能触达的一切都要换——数据库密码、对象存储凭证、第三方 API key、CI/CD 里的 secrets、镜像仓库 token。泄露一把通常意味着整套凭证都该换
  5. 重建而不是清理:一旦确认已获得 root,在原机上清理是不够的,持久化可能藏在没查到的地方。从可信镜像或干净快照重建,只迁移经过检查的数据
  6. 复盘:写下时间线(何时发现、哪些凭证受影响、是否被使用过),按影响面通知相关方,并把这次发现变成一条告警规则

如果泄露的凭证在被吊销前被实际使用过,就要按数据泄露事件处理:评估哪些数据被访问、是否需要对外通报,而不是只当成一次配置错误关掉工单。

怎么验证:15 分钟自检清单

基线应该是可以在 15 分钟内验证的东西。换个终端,按顺序跑下面这些:

  1. SSH 生效配置:sudo sshd -T | grep -Ei "permitrootlogin|passwordauthentication",期望看到两项均为 no
  2. 对外暴露面(从另一台机器跑):nmap -Pn your.server.ip,只应出现 22/80/443 及你有意开放的端口
  3. 本机监听:ss -tulpn | grep LISTEN,数据库与缓存的监听地址应为 127.0.0.1 或内网地址
  4. 防火墙规则:sudo ufw status verbose(或 sudo firewall-cmd --list-all),默认策略应为拒绝或仅白名单
  5. 待更新包:sudo apt list --upgradable(Debian 系)/ dnf check-update(RHEL 系)
  6. 失败登录:lastb -ai | head -20,出现陌生 IP 段就继续追
  7. SUID 文件与计划任务:sudo find / -xdev -perm -4000 -type f 2>/dev/null、crontab -l、ls -la /etc/cron.d/
  8. 仓库密钥扫描:git ls-files | xargs grep -nEi "akia|secret|password",有命中就按已泄露处理

把这 8 条写进每月一次的例行检查,或者做成 CI 里的基线任务。能被自动化的加固才叫基线,只做一次的只是改过一次配置。

下一步:挑一台已经上线的机器跑完这 8 条,把命中的项分成「5 分钟能改完」和「需要排期」两栏——前一栏今天清掉,后一栏进发版窗口,写清负责人和日期。账号侧的另一半风险(来源不明的账号、共用支付方式、被牵连封禁)不在这 9 项里,单独见 云账号被封的 5 类原因与预防清单。

本文给的是跨厂商通用的最小集。具体到你用的云厂商,安全组默认值说明与最佳实践文档可能更严格(例如强制 IMDSv2、默认拒绝入站),以官方文档实时内容为准。

按自己的用量算一遍?

告诉我们区域和配置,工程师给出配置建议与报价;支持 USDT TRC-20 付款。

立即充值