Linux服务器安全加固实战:从SSH、用户权限到防火墙配置全面解析

发布时间:2026/10/2 4:08:18
Linux服务器安全加固实战:从SSH、用户权限到防火墙配置全面解析 引言默认配置就是最大的攻击面一台刚交付的云主机默认状态通常是这样的22 端口对全网开放、允许 root 用密码直接登录、防火墙处于关闭或全放行状态、系统里躺着十几个从没人用过的交互式账户。把它挂上公网不出 24 小时/var/log/secure里就会堆满来自全球各地的暴力破解记录——这已经是被验证过无数次的常态。真正的痛点不是不知道该加固而是加固做不完整、做错了顺序甚至把自己锁在门外。很多团队的做法是改个 SSH 端口、装个 Fail2ban然后心安理得。但攻击者一旦通过某个被遗忘的弱口令账户进来剩下的横向移动几乎是畅通无阻的。一个真实案例是某创业公司上线了一台测试机只把 SSH 端口从 22 改成了 2222密码认证没关也没做账户清理。三天后服务器 CPU 跑满排查发现攻击者用离职员工留下的test账户登录——该账户口令是test123从未被禁用。攻击者进来后写入挖矿程序并尝试用~/.ssh里的旧密钥横向连接内网其他机器。这个案例说明单点加固无效必须让网络、身份、权限三个平面同时收敛缺一不可。本文不罗列100 条安全清单而是围绕三个平面讲清加固的底层逻辑并给出一套可直接落地的顺序化操作流程。一、加固的底层模型三个平面的收敛任何一台 Linux 服务器的访问控制都可以拆成三个平面平面回答的问题对应机制网络平面谁的网络包能到达这台机器云安全组、firewalld/nftables身份平面连上来的人是谁如何证明SSH 密钥、PAM、密码策略权限平面证明身份后能做什么sudo、SELinux、文件权限、Capabilities加固的本质就是在这三个平面上做攻击面收敛遵循四条原则默认拒绝Default Deny、最小权限Least Privilege、纵深防御Defense in Depth、可审计可回滚。顺序上一定是先网络、再身份、最后权限。反过来做你会先失去连接。这三条原则不是口号它们各自有非常具体的工程含义。默认拒绝意味着每一条放行规则都必须有明确的业务理由而不是先开着以后再说最小权限意味着任何一个身份人、进程、服务拿到的权限应该刚好够它完成工作多一分都不要纵深防御意味着不要指望任何单一机制SSH 密钥失效时还有防火墙防火墙被绕过后还有 SELinux可审计可回滚则是最容易被忽略的一条——所有加固动作都要能回答谁在什么时候改了什么并且能在改坏时快速回退。还有一个容易被忽视的维度时间。加固不是一次性动作而是一个持续过程。系统上线时是安全的不代表三个月后还是安全的——新装的软件可能开了新端口新入职的同事可能加了一个弱口令账户某个服务升级后可能把 SELinux 策略重置了。所以本文后面会专门讲审计与监控让加固可持续。一个常见的顺序反例是管理员先登录服务器把/etc/passwd、/etc/shadow权限收紧又关闭了 root 登录结果发现自己唯一的普通账户还没加 sudo 权限SSH 配置又写错了最终只能通过云控制台的 VNC 救援。正确的做法是先在网络平面确认只允许自己的管理 IP 访问 SSH再在身份平面配置好普通账户和密钥最后才在权限平面做 sudo 与文件权限收敛。每一步都保留一条可回退的通道。二、SSH 加固把住唯一的入口2.1 用密钥认证彻底取代密码密码认证的根本问题是它可被猜测。ed25519 密钥在 256 位安全强度下密钥长度只有 68 字节比 RSA-4096 更短、更快、更安全。# 客户端生成 ed25519 密钥对ssh-keygen-ted25519-a100-Copsexample.com-2024-f~/.ssh/id_ed25519_prod# 参数逐条解释# -t ed25519 指定密钥类型基于 Curve25519 椭圆曲线抗侧信道# -a 100 KDF 轮数对私钥口令做 100 轮派生暴力破解成本指数级上升# -C 注释强烈建议写清用途归属年份多人协作时这是审计线索# -f 私钥输出路径不同环境用不同密钥避免一把钥匙开所有门# 分发公钥到服务器推荐 ssh-copy-id它会自动处理目录与权限ssh-copy-id-i~/.ssh/id_ed25519_prod.pub ops203.0.113.10# 若环境没有 ssh-copy-id可手工追加注意 umask 077 防止权限过宽cat~/.ssh/id_ed25519_prod.pub|sshops203.0.113.10\umask 077; mkdir -p ~/.ssh cat ~/.ssh/authorized_keys密钥认证的安全性来自非对称密码学私钥永远不离开客户端认证时服务器发一段随机 challenge客户端用私钥签名后回传服务器用authorized_keys里的公钥验证签名。整个过程私钥不上网、密码不传输中间人即使抓包也拿不到任何可用于登录的东西。这和密码认证有本质区别——密码在网络里哪怕是加密通道里是可被重放的凭证而签名是一次性的、绑定本次会话的。生成之后服务端的权限必须严格校准否则 sshd 会因为权限过宽直接拒绝使用该密钥# 服务端权限收敛chmod700~/.sshchmod600~/.ssh/authorized_keyschmod600~/.ssh/id_ed25519_prod# 私钥只有属主可读写chmod644~/.ssh/id_ed25519_prod.pub# 公钥可以宽松# 关键家目录本身不能被 group/other 写否则 sshd 的 StrictModes 会拒绝chmodg-w,o-w ~这里有一个极其常见的坑很多人只改了.ssh和authorized_keys的权限却忘了家目录。sshd 的StrictModes yes默认开启会检查整条路径只要家目录是775或777公钥认证就会失败而日志里往往只写一句含糊的Authentication refused: bad ownership or modes。排查时用namei -l ~/.ssh/authorized_keys可以一次性看到路径上每一级的权限。如果系统启用了 SELinux还要确认文件的上下文标签正确restorecon-Rv~/.ssh# 递归恢复默认上下文ls-Z~/.ssh/authorized_keys# 正常应显示 ssh_home_t手工cp或scp过来的文件经常带着user_home_t之类的标签SELinux 会默默拦掉而journalctl -u sshd里会出现 AVC 拒绝记录。用ausearch -m avc -ts recent可以快速定位。常见问题FAQ为什么我配置了密钥登录时还是提示输入密码第一检查服务端sshd_config中PubkeyAuthentication是否为yes且没有被Include文件覆盖第二检查authorized_keys是否在正确用户的家目录下文件属主是否为该用户第三用ssh -vvv opshost查看客户端调试输出重点看Offering public key和Server accepts key两行第四确认AllowUsers或AllowGroups是否包含该用户。多数情况下问题出在权限或 SELinux 上下文而不是密钥本身。密钥轮换与备份建议生产密钥建议每年至少轮换一次离职人员密钥立即从authorized_keys移除。可以在authorized_keys每行末尾用#注释标注归属和过期时间例如ssh-ed25519 AAA... opsexample.com-2024#expire2025-12-31。私钥必须加密存储并保留一份离线备份但不要把私钥放在跳板机或 CI 系统的明文变量里。2.2 sshd_config 的关键参数逐条讲清为什么不要直接在/etc/ssh/sshd_config里改而是用Include引入一个独立的加固片段OpenSSH 7.3 支持这样升级时不会被覆盖回滚也只需要删一个文件# /etc/ssh/sshd_config.d/99-hardening.conf# ---- 监听与入口 ----Port22022# 换端口只减少扫描噪声不是安全边界AddressFamily inet# 只用 IPv4避免 IPv6 规则被遗忘ListenAddress0.0.0.0# ---- 身份认证 ----PermitRootLogin no# 彻底禁止 root 直连改用普通账户 sudoPasswordAuthentication no# 关闭密码只留公钥PermitEmptyPasswords no# 空口令账户一律拒绝KbdInteractiveAuthentication no# 关闭键盘交互除非上双因素ChallengeResponseAuthentication no PubkeyAuthenticationyesAuthenticationMethods publickey# 显式声明只允许公钥防止配置被覆盖后回退# ---- 认证节流 ----MaxAuthTries3# 单连接最多 3 次认证失败即断开MaxSessions4# 单连接最多 4 个会话限制复用隧道LoginGraceTime30# 30 秒内未完成认证就断开压缩慢速攻击窗口ClientAliveInterval300# 每 5 分钟探活一次ClientAliveCountMax2# 连续 2 次无响应则断开回收僵尸会话# ---- 账户白名单 ----AllowUsers deploy ops# 只允许这两个账户登录AllowGroups sshusers# 或者用组来管理便于批量授权# ---- 功能面收敛 ----X11Forwarding no# 服务器不需要转发 X11AllowAgentForwarding no# 关闭 agent 转发防止跳板机窃取私钥AllowTcpForwarding no# 不需要隧道就关掉需要时再按用户开PermitTunnel no GatewayPorts no# ---- 日志 ----UsePAMyesLogLevel VERBOSE# 记录密钥指纹便于审计谁用了哪把钥匙逐条说一下容易被误解的地方PermitRootLogin no而不是prohibit-password。后者允许 root 用密钥登录看似安全但它保留了root 是一个可登录身份这一事实。一旦某台跳板机上的 root 私钥泄露攻击者直接就是 root。正确做法是所有人用普通账户登录需要提权时走sudo让每一次提权都留下审计记录。AuthenticationMethods publickey是锁死而非默认。如果只写PasswordAuthentication no某次配置合并或软件升级可能把它改回来。显式声明AuthenticationMethods后即使PasswordAuthentication被改成yes认证方法仍然只认公钥。这是纵深防御在配置层面的体现。MaxAuthTries 3与LoginGraceTime 30是一对。前者限制每次连接能试几次密码后者限制每次连接能占用多久。只改一个攻击者仍可以用大量并发连接慢慢试。两个一起收紧单 IP 的爆破速率会被压到很低。AllowUsers是最容易被低估的一道闸。系统里可能有一堆你不知道的服务账户它们理论上不该登录但默认并没有被禁止。加上白名单后即使某个账户被设了弱口令只要不在名单里SSH 这一层就进不来。实战踩坑Include文件不生效。OpenSSH 读取Include的顺序是从上到下如果sshd_config主文件里Include写在了某个参数之后后面的参数可能覆盖前面的。建议把Include /etc/ssh/sshd_config.d/*.conf放在主文件最顶部并确保片段文件以99-这类靠后的数字命名。改完后用sshd -T | grep -i include确认加载顺序用sshd -T | grep -E permitrootlogin|passwordauthentication|allowusers检查最终生效值。优化建议用Match块做差异化策略。如果确实有自动化账户需要 TCP 转发不要全局放开而是精确授权# 只对 tunneluser 开放转发并限制目标地址Match User tunneluser AllowTcpForwardingyesPermitOpen db.internal:3306 ForceCommand /bin/falseForceCommand /bin/false让该账户无法获得交互式 shell只能做端口转发。这样既满足业务又不会把整个服务器的转发能力暴露给所有人。改完之后永远先校验再重载sshd-t# 语法校验配置写错会在这里报出来sshd-T|head-50# 打印最终生效配置确认没有被其它文件覆盖systemctl reload sshd# 用 reload 而不是 restart不断开已有连接reload是这里的生命线。restart会杀掉当前所有 SSH 会话如果你只有一条连接、配置又写错了那就直接失联。reload只让新连接使用新配置已有会话保持不变给你留了一条验证新配置是否可用的退路。务必先开一个新终端验证能登录再关闭旧终端。2.3 双因素与 Fail2ban把暴力破解的成本抬到不划算公钥认证已经很强但在合规场景等保、PCI-DSS下往往还要求双因素。SSH 上最轻量的做法是publickey TOTP# 服务端安装yuminstall-ygoogle-authenticator# 或 apt install libpam-google-authenticator# 为指定用户生成 TOTP 配置会输出二维码和备用码务必备份google-authenticator-t-d-f-r3-R30-w3# -t 使用 TOTP基于时间而非 HOTP基于计数# -d 禁止重复使用同一验证码# -f 写入 ~/.google_authenticator# -r 3 -R 30 限速30 秒内最多 3 次尝试# -w 3 允许前后 3 个时间窗的时钟漂移然后在/etc/pam.d/sshd顶部加一行并把 sshd 的认证方法改成两步# /etc/pam.d/sshd 第一行auth required pam_google_authenticator.so nullok# nullok 表示没配置 TOTP 的用户仍可登录全量上线后应去掉# sshd 配置KbdInteractiveAuthenticationyesAuthenticationMethods publickey,keyboard-interactive注意顺序publickey,keyboard-interactive表示先验公钥再验 TOTP两者必须都过。如果写成keyboard-interactive,publickey顺序就反了。改完同样要sshd -treload并且先留一个已登录的会话。TOTP 常见问题验证码总是错误。九成以上是服务器时间不同步。TOTP 依赖时间窗口服务器与手机时间差超过 30 秒就可能失败。用chronyc tracking或timedatectl确认 NTP 同步状态必要时重启chronyd。另外-w 3虽然容忍时钟漂移但也会略微降低安全性内网可设 1 到 2公网建议保持 3。Fail2ban 解决的是另一个问题即使密码认证关了日志里仍然会有大量无效连接尝试占用连接数、污染日志。Fail2ban 通过读日志、识别失败模式、调用防火墙封禁来源 IP 来降低噪声# /etc/fail2ban/jail.d/sshd.local [sshd] enabled true port 22022 filter sshd backend systemd # 现代 systemd 系统优先用 systemd 后端 maxretry 3 findtime 10m bantime 24h bantime.increment true # 累犯递增封禁 bantime.factor 2 bantime.maxtime 4w ignoreip 127.0.0.1/8 ::1 203.0.113.0/24 198.51.100.7 # ignoreip 必须写本地回环、办公网出口、监控探针、跳板机 # 否则很容易把健康检查或自己的办公 IP 封掉ignoreip是这里最重要的配置。真实事故里最常见的场景是某天在家办公IP 变了连错两次密码Fail2ban 直接封了 24 小时而你又没有控制台权限只能干等。另一个常见事故是云厂商的负载均衡健康检查源 IP 被误封导致服务被判定为不健康而摘除。上线 Fail2ban 之前先把所有合法但会失败的来源列出来全部加进 ignoreip。验证与排查fail2ban-client status sshd# 看当前封禁列表与统计fail2ban-clientsetsshd unbanip1.2.3.4tail-f/var/log/fail2ban.log如果fail2ban-client status sshd显示Total failed: 0通常是backend配错了用systemd后端时读的是 journald用auto/文件后端时读的是/var/log/secureRHEL 系或/var/log/auth.logDebian 系。日志系统不一致Fail2ban 就看不见攻击。另一个常见问题是 Fail2ban 的封禁动作与 firewalld 冲突导致规则被覆盖。可以用fail2ban-client get sshd actions查看当前动作必要时显式指定banaction firewallcmd-ipset或banaction nftables-multiport。2.4 会话与转发的收敛SSH 不只是一个登录通道它还是隧道、转发、代理。默认开启的很多能力在服务器场景下根本用不到却给攻击者提供了横向移动的跳板Agent forwarding开启后服务器上的 root 可以借用你本地 ssh-agent 里的私钥去登录你能登录的任何机器。跳板机一旦被拿下攻击者就能顺着 agent 一路横向。需要跳板时用ProxyJump而不是 agent 转发# 客户端 ~/.ssh/configHost jump HostName203.0.113.10 User ops Port22022IdentityFile ~/.ssh/id_ed25519_prod Host backend HostName10.0.0.20 User deploy ProxyJump jump IdentityFile ~/.ssh/id_ed25519_prod这样本地 SSH 会先连接 jump再通过它建立到 backend 的加密通道私钥始终只在本地使用jump 上不残留任何可用于登录 backend 的凭证。ProxyJump替代了早期的ProxyCommand nc写法更简洁也更安全。如果必须用 agent forwarding至少用ssh-add -t 300设置私钥在 agent 中的存活时间并避免在跳板机上以 root 身份操作。TcpForwarding如果业务确实需要隧道不要全局AllowTcpForwarding yes而是用Match User tunneluser只对特定账户开放并配合PermitOpen限制可转发的目标。前面 2.2 的Match示例已经给出这里再强调一次PermitOpen是白名单只允许列出的目标地址和端口能有效防止攻击者把服务器当成内网扫描代理。X11ForwardingX11 转发不仅会启动额外进程还可能把服务器的 X 授权信息暴露给客户端。现代运维几乎不需要它关闭是零成本。如果确实需要运行图形程序优先使用 VNC 或 Web 终端而不是 X11 转发。PermitTunnel允许 tun 设备隧道等于把服务器变成 VPN 端点。更多硬核网安与AI工具包请扫码获取完整源码除非明确要做 VPN 网关否则关闭。开启后攻击

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询