CentOS 7 SSH安全加固实战:认证、会话、审计与等保合规
1. 为什么SSH加固不是“加个密码就完事”的事在CentOS 7的运维现场我见过太多次这样的场景新装系统后随手改个root密码开个sshd服务就直接扔进生产环境——结果不到48小时/var/log/secure里密密麻麻全是来自巴西、罗马尼亚、越南IP的暴力破解记录失败登录尝试每分钟超20次再过几天lastb命令一查十几个陌生IP已成功登录过某天凌晨三点监控告警说CPU持续100%——进去一看/tmp/.X11-unix/下藏着一个伪装成kthreadd的挖矿进程SSH后门早已被植入。这不是危言耸听。CentOS 7虽已进入维护阶段EOL于2024年6月30日但大量政企内网、教育平台、老旧业务系统仍在稳定运行。而OpenSSH作为其默认远程管理通道恰恰是攻击者最优先瞄准的入口。SSH安全加固的本质不是给门上多加一把锁而是重构整套门禁系统从谁有资格敲门认证机制、敲门时要出示什么证件凭证强度、门开多宽多长时间会话控制、进门后能走到哪间屋权限隔离到每次开门是否留痕可查审计追踪——缺一不可。本文聚焦CentOS 7这一特定环境不谈泛泛而谈的“修改端口”“禁用root”而是基于三年来为27家单位做基线加固的真实经验拆解每一项配置背后的攻击面逻辑、参数取舍依据、实测兼容性边界以及那些藏在man sshd_config文档第17页 footnote 里的关键细节。适合刚通过yum install -y openssh-server完成基础部署的中级运维也适合需要出具等保2.0三级整改报告的安全工程师——所有操作均在真实物理服务器VMware虚拟机双环境验证配置项全部标注RHEL/CentOS 7.9最小化安装下的生效状态。提示本文所有加固操作均需通过本地console或带外管理如iDRAC/iLO执行。切勿在仅依赖SSH远程连接时直接修改sshd_config并重启服务否则可能永久失联。我曾在某高校教务系统上因未预留console通道执行systemctl restart sshd后触发SELinux策略冲突导致服务无法启动最终靠重启服务器进单用户模式才救回。2. 认证机制重构从密码裸奔到多因子可信链2.1 密码策略的硬性落地不只是/etc/pam.d/system-auth很多人以为改了/etc/ssh/sshd_config里的PasswordAuthentication no就万事大吉却忽略了PAMPluggable Authentication Modules才是密码强度的实际守门人。CentOS 7默认的pam_pwquality.so模块虽存在但若未显式启用并配置参数passwd命令仍允许设置123456这类弱口令。我们先看一个典型漏洞场景某政务云平台管理员为图省事将所有运维账号密码设为Admin2023加序号如Admin202301。攻击者通过泄露的员工邮箱列表批量生成字典配合Hydra工具在37分钟内爆破出12个有效账户——问题根源不在SSH配置而在PAM未强制密码复杂度。实操步骤与参数详解编辑/etc/pam.d/system-auth在password requisite pam_pwquality.so行后追加以下参数password requisite pam_pwquality.so try_first_pass local_users_only retry3 authtok_type minlen12 dcredit-1 ucredit-1 lcredit-1 ocredit-1 difok4 maxrepeat3 reject_username enforce_for_root逐项解释其防御逻辑minlen12强制最小长度12位非8位实测显示8位密码在GPU集群下平均破解时间2小时dcredit-1等四参数要求必须含数字、大写、小写、特殊字符各至少1个负值表示“至少需要”difok4新密码与旧密码至少4个字符不同防止Password1→Password2式弱变更maxrepeat3禁止连续重复字符超过3次拦截aaaaa类密码reject_username密码不得包含用户名防adminadmin123类组合注意enforce_for_root参数常被忽略。CentOS 7默认root密码不受PAM策略约束此参数强制root账户同样遵循规则。测试时可用sudo passwd root触发校验若提示BAD PASSWORD: The password fails the dictionary check即生效。验证方式# 检查当前策略是否加载 grep pam_pwquality /etc/pam.d/system-auth # 测试弱密码拒绝效果需切换非root用户操作 echo -e oldpass\n123456 | passwd testuser 21 | grep BAD PASSWORD2.2 公钥认证的工业级实践不止于ssh-copy-id公钥认证是SSH加固的基石但多数人停留在ssh-keygen -t rsa -b 4096生成密钥、ssh-copy-id推送的初级阶段。这存在三个致命隐患RSA算法在2023年已被NIST建议逐步淘汰私钥未加密存储authorized_keys文件权限宽松导致篡改风险。升级方案Ed25519密钥 密码保护 严格权限控制密钥生成客户端执行# 生成Ed25519密钥比RSA4096快3倍抗量子计算潜力更强 ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -C admincompany.com # -a 100 表示密钥派生使用100次PBKDF2迭代大幅提升暴力破解难度 # -C 添加注释便于识别密钥归属服务端密钥部署关键避免常见错误# 创建专用目录存放公钥非直接写入~/.ssh/authorized_keys mkdir -p /etc/ssh/keys/admin chmod 700 /etc/ssh/keys/admin # 将公钥内容写入独立文件便于按用户粒度管理 cat id_ed25519.pub /etc/ssh/keys/admin/id_ed25519.pub chmod 600 /etc/ssh/keys/admin/id_ed25519.pub # 修改sshd_config启用公钥认证 echo PubkeyAuthentication yes /etc/ssh/sshd_config echo AuthorizedKeysFile /etc/ssh/keys/%u/id_ed25519.pub /etc/ssh/sshd_config权限加固90%的教程遗漏此步# 修复常见权限错误sshd对~/.ssh目录要求700文件要求600 chmod 700 /root/.ssh chmod 600 /root/.ssh/authorized_keys chown root:root /root/.ssh /root/.ssh/authorized_keys # 防止用户自行修改authorized_keys针对普通用户 chmod 644 /home/testuser/.ssh/authorized_keys chown testuser:testuser /home/testuser/.ssh/authorized_keys踩坑实录某金融客户曾因/root/.ssh/authorized_keys权限为644被恶意脚本注入command/bin/bash前缀导致所有密钥登录后自动执行后门命令。Ed25519密钥本身无法防范此类应用层劫持必须配合严格的文件权限和SELinux上下文见3.3节。2.3 多因子认证MFA的轻量集成Google Authenticator实战对于等保2.0三级系统仅凭密钥或密码无法满足“双因素认证”要求。Google Authenticator是CentOS 7生态中最成熟的开源MFA方案无需额外服务器且与SSHD深度集成。部署流程服务端执行# 安装EPEL源及组件 yum install epel-release -y yum install google-authenticator-libpam -y # 为root用户初始化MFA生成密钥、二维码、备用码 google-authenticator -t -d -f -r 3 -R 30 -w 3 # 参数说明 # -t : 基于时间的TOTP非HOTP # -d : 禁用设备名称检查适配云服务器动态hostname # -f : 强制写入~/.google_authenticator避免交互 # -r 3 : 30秒窗口内最多3次重试防暴力 # -R 30 : 30秒内禁止重复使用同一验证码 # -w 3 : 容忍前后3个时间窗口解决时钟漂移配置PAM集成编辑/etc/pam.d/sshd在auth [successdone new_authtok_reqddone defaultbad]行前插入auth [successok new_authtok_reqdok defaultbad] pam_google_authenticator.so nullok secret/root/.google_authenticatorsshd_config关键配置# 启用键盘交互认证MFA必需 ChallengeResponseAuthentication yes # 强制MFA与公钥同时验证顺序很重要 AuthenticationMethods publickey,keyboard-interactive实测技巧首次配置后务必保留备用验证码Backup Codes并用手机扫描二维码同步。若服务器时间偏差30秒需用ntpdate -s time.windows.com校时否则MFA始终失败。某三甲医院因NTP服务未启用导致全院SSH登录全部中断2小时。3. 连接与会话控制把攻击者的“试错成本”提到最高3.1 登录限制的精准打击fail2ban vs firewall-cmd单纯用iptables封IP是粗放式防御。fail2ban能动态分析/var/log/secure日志对暴力破解行为实施自适应封禁但CentOS 7默认firewalld与iptables共存易引发冲突。我们的方案是firewalld定义白名单基础策略fail2ban处理动态威胁。firewalld白名单配置最小化开放# 仅允许运维管理网段如192.168.10.0/24访问SSH firewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.10.0/24 port port22 protocoltcp accept # 拒绝所有其他来源显式声明避免firewalld默认策略歧义 firewall-cmd --permanent --add-rich-rulerule familyipv4 port port22 protocoltcp reject firewall-cmd --reloadfail2ban深度配置/etc/fail2ban/jail.local[sshd] enabled true filter sshd logpath /var/log/secure maxretry 3 # 3次失败即封禁比默认5次更激进 bantime 3600 # 封禁1小时避免误封 findtime 600 # 10分钟内累计3次失败才触发 action %(action_mwl)s # 同时向管理员邮箱发送告警 # 同时写入自定义日志供SIEM采集关键增强自定义过滤器应对新型攻击创建/etc/fail2ban/filter.d/sshd-custom.conf添加对Invalid user和User .* from的精准匹配[Definition] failregex ^%(__prefix_line)s(?:error: PAM: )?Authentication failure for .* from HOST\s*$ ^%(__prefix_line)sFailed (?:password|publickey) for .* from HOST(?: port \d*)?(?: ssh\d*)?$ ^%(__prefix_line)sInvalid user .* from HOST\s*$ ignoreregex 经验数据在某省级政务云部署中启用此配置后暴力破解成功率从日均127次降至0封禁IP平均停留时间42分钟且92%的攻击源在首次尝试后即放弃。fail2ban的bantime不宜设为永久-1否则可能因IP池枯竭导致合法用户被误伤。3.2 SSH会话的生存周期管理KillIdle与ClientAlive协同默认SSH会话无超时限制管理员忘记登出或网络异常断连后空闲会话长期驻留成为提权跳板。CentOS 7的ClientAliveInterval与ClientAliveCountMax需与系统级TMOUT联动。sshd_config配置/etc/ssh/sshd_config# 服务端主动探测每300秒发一次心跳包 ClientAliveInterval 300 # 连续3次无响应则断开连接总超时15分钟 ClientAliveCountMax 3 # 强制用户shell超时覆盖用户自定义的TMOUT ForceCommand /bin/bash -c export TMOUT900; exec $SHELL系统级超时强化/etc/profile# 所有用户登录后15分钟无操作自动退出 if [ $PS1 ]; then export TMOUT900 readonly TMOUT export HISTTIMEFORMAT%F %T export HISTSIZE10000 fi验证方法# 查看当前会话超时设置 echo $TMOUT # 模拟空闲超时在另一终端执行 sleep 910 echo should be disconnected注意事项ForceCommand会覆盖用户.bashrc中的TMOUT设置确保策略统一。某能源企业曾因未设readonly TMOUT被运维人员在.bashrc中设为0导致超时失效最终空闲会话被利用执行横向移动。3.3 SELinux上下文加固让恶意进程寸步难行CentOS 7默认启用SELinux但多数加固指南忽略其对SSH进程的保护价值。当攻击者通过漏洞获取shell后SELinux可阻止其执行敏感操作如读取/etc/shadow、加载内核模块。关键策略配置# 启用SSH相关的SELinux布尔值 setsebool -P ssh_sysadm_login on # 允许sysadm角色登录 setsebool -P use_nfs_home_dirs off # 禁用NFS home目录防挂载劫持 setsebool -P allow_ssh_keysign on # 允许密钥签名支持证书认证 # 检查sshd进程SELinux上下文 ps -eZ | grep sshd # 正常应显示system_u:system_r:sshd_t:s0-s0:c0.c1023 # 若为unconfined_u:unconfined_r:unconfined_t:s0则需恢复默认策略 restorecon -Rv /etc/ssh /var/log/secure自定义策略示例防SSH后门创建/root/sshd_custom.te限制sshd_t域的危险能力module sshd_custom 1.0; require { type sshd_t; type initrc_exec_t; class file { execute_no_trans open read }; } # 禁止sshd执行init脚本防后门持久化 dontaudit sshd_t initrc_exec_t:file execute_no_trans;编译并加载checkmodule -M -m -o sshd_custom.mod sshd_custom.te semodule_package -o sshd_custom.pp -m sshd_custom.mod semodule -i sshd_custom.pp实战价值某银行核心系统遭入侵后攻击者试图通过/usr/bin/ssh调用/etc/init.d/malware start启动后门因SELinux策略拒绝execute_no_trans权限而失败为应急响应赢得23分钟黄金时间。4. 审计与监控闭环让每一次连接都可追溯、可归因4.1 SSH登录日志的精细化采集从secure到journalctl的演进CentOS 7默认将SSH日志写入/var/log/secure但该文件易被攻击者清空。journalctl提供结构化、防篡改的日志存储且支持按字段过滤。启用持久化日志# 创建日志存储目录 mkdir -p /var/log/journal # 重启journald服务 systemctl kill --kill-whomain --signalSIGUSR1 systemd-journald # 验证日志持久化 journalctl --disk-usage # 应显示非0值关键审计事件提取每日巡检脚本#!/bin/bash # /root/scripts/ssh_audit.sh # 1. 统计昨日所有SSH登录成功失败 echo SSH登录统计昨日 journalctl -S yesterday -u sshd | grep Accepted\|Failed\|Invalid | wc -l # 2. 提取高危操作root登录密码认证 echo -e \n 高危登录行为 journalctl -S yesterday -u sshd | awk /Accepted/ /password/ /root/{print $1,$2,$3,$9,$11} | sort | uniq -c | sort -nr # 3. 检测异常地理IP需提前配置IP库 echo -e \n 异常IP登录 journalctl -S yesterday -u sshd | grep Failed | awk {print $13} | sort | uniq -c | sort -nr | head -10日志轮转优化/etc/logrotate.d/sshd/var/log/secure { weekly missingok notifempty create 0600 root root sharedscripts postrotate /bin/kill -HUP cat /var/run/syslogd.pid 2/dev/null 2/dev/null || true # 同步日志到远程SIEM scp /var/log/secure.* adminsiem-server:/logs/centos7/ endscript }关键洞察journalctl日志默认保存在内存中必须执行systemctl kill --signalSIGUSR1 systemd-journald才能强制写入磁盘。某交通指挥中心因未配置持久化遭遇勒索软件后无法还原攻击时间线导致取证失败。4.2 进程行为审计auditd监控SSH相关系统调用auditd是Linux内核级审计框架可捕获execve、openat等关键系统调用即使攻击者删除日志也能留存证据。配置SSH审计规则/etc/audit/rules.d/ssh.rules# 监控sshd二进制文件执行 -a always,exit -F path/usr/sbin/sshd -F permx -k ssh_exec # 监控SSH配置文件读取 -a always,exit -F path/etc/ssh/sshd_config -F permr -k ssh_config # 监控密钥文件访问 -a always,exit -F path/etc/ssh/keys/ -F dir -F permr -k ssh_keys # 监控PAM配置变更 -a always,exit -F path/etc/pam.d/sshd -F permwa -k pam_ssh加载规则并验证# 重新加载audit规则 augenrules --load # 检查规则是否生效 ausearch -m execve -ts recent -k ssh_exec | head -5 # 实时监控SSH相关事件 auditctl -w /etc/ssh/sshd_config -p wa -k ssh_config_change告警脚本/root/scripts/audit_alert.sh#!/bin/bash # 当检测到sshd_config被修改时发送邮件告警 if ausearch -m CONFIG_CHANGE -ts $(date -d 1 minute ago %H:%M:%S) | grep -q sshd_config; then echo ALERT: /etc/ssh/sshd_config modified at $(date) | mail -s SSH Config Alert admincompany.com fi深度技巧ausearch查询时需注意时间格式-ts recent比-ts today更精准。某证券公司通过此规则发现运维人员私自添加PermitRootLogin yes在配置生效前37秒截获并阻断。4.3 网络层连接溯源tcpdump与ss命令的黄金组合当高级持续性威胁APT绕过常规日志需在网络层抓包分析。ss命令比netstat更高效tcpdump可捕获原始流量。实时连接分析排查可疑会话# 显示所有SSH连接含进程名和用户 ss -tunap | grep :22 # 输出示例ESTAB 0 0 192.168.10.100:22 103.21.56.178:54321 users:((sshd,pid1234,fd3),(sshd,pid1235,fd4)) # 按用户统计连接数 ss -tunap | grep :22 | awk {print $7} | cut -d, -f1 | sort | uniq -c | sort -nr针对性抓包定位异常流量# 抓取来自可疑IP的SSH流量保存为pcap供Wireshark分析 tcpdump -i any -w /tmp/ssh_suspicious.pcap host 103.21.56.178 and port 22 -c 1000 # 提取TCP流中的明文信息如密码输入需谨慎使用 tcpdump -i any -A host 103.21.56.178 and port 22 | grep -E (password|Password|PASS)安全红线tcpdump抓包需获得书面授权且严禁在生产数据库服务器等高敏节点执行。某运营商因未授权抓包导致核心网元CPU飙升至98%触发业务中断。5. 加固后的验证与持续运营别让配置变成“一次性快照”5.1 自动化验证脚本5分钟完成32项检查人工逐条验证加固效果效率低下。我们开发了ssh-hardening-check.sh脚本覆盖所有关键项#!/bin/bash # CentOS 7 SSH加固验证脚本 checks0 failed0 # 检查1密码认证是否禁用 if grep -q ^PasswordAuthentication[[:space:]]*no /etc/ssh/sshd_config; then ((checks)) else echo [FAIL] PasswordAuthentication not disabled ((failed)) fi # 检查2PAM密码策略是否启用 if grep -q pam_pwquality.so /etc/pam.d/system-auth; then ((checks)) else echo [FAIL] pam_pwquality not configured ((failed)) fi # ... 共32项检查略去中间代码 echo 总结 echo 总检查项: $checks echo 失败项: $failed if [ $failed -eq 0 ]; then echo ✅ 所有加固项验证通过 else echo ❌ 发现$failed处配置异常请核查 fi执行与输出chmod x ssh-hardening-check.sh ./ssh-hardening-check.sh # 输出示例 # 总结 # 总检查项: 32 # 失败项: 0 # ✅ 所有加固项验证通过运维建议将此脚本加入cron每日凌晨2点执行并将结果邮件发送至安全团队。某省大数据局通过此机制在加固后第17天发现某台测试服务器因配置同步失败PubkeyAuthentication被意外关闭及时修复。5.2 等保2.0三级合规映射每一项配置对应哪个条款等保测评常被视作“填表工程”实则每项技术措施都有明确标准依据。以下是CentOS 7 SSH加固与等保2.0三级核心条款的映射关系等保条款对应加固措施验证方法8.1.4.2 身份鉴别Ed25519密钥MFA双因子ssh -i id_ed25519 userhost需输入6位验证码8.1.4.3 访问控制firewalld白名单fail2bannmap -p22 192.168.10.100仅白名单IP可达8.1.4.4 安全审计auditd规则journalctl持久化ausearch -k ssh_config可查历史修改记录8.1.4.5 剩余信息保护TMOUT900会话超时last -i显示会话时长≤15分钟8.1.4.6 入侵防范SELinux策略sshd_t域限制sesearch -A -s sshd_t -t shadow_t无allow规则合规提示向测评机构提供/root/ssh_hardening_report.pdf含脚本输出、配置截图、日志样本比口头解释更高效。某央企在等保复测中因提前准备此报告测评时间缩短40%。5.3 持续运营的三个关键动作加固不是终点而是持续运营的起点。我们总结出必须坚持的三项动作1. 密钥生命周期管理每90天轮换# 生成新密钥对 ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519_2024Q3 -C Q3-rotation # 推送新公钥并保留旧密钥过渡期7天 ssh-copy-id -i ~/.ssh/id_ed25519_2024Q3.pub userhost # 7天后删除旧密钥 sed -i /old_key_comment/d /etc/ssh/keys/user/id_ed25519.pub2. 配置变更审计Git版本控制# 将SSH配置纳入Git管理 cd /etc/ssh git init git add . git commit -m Initial SSH config commit git remote add origin https://gitlab.company.com/infra/centos7-ssh-config.git git push -u origin master3. 红蓝对抗演练每季度邀请内部红队使用hydra -L users.txt -P passwords.txt -t 4 ssh://target进行渗透测试验证fail2ban封禁时效、MFA绕过可能性、日志完整性。某市政务云通过此演练发现AuthenticationMethods配置未启用keyboard-interactive导致MFA形同虚设及时修正。最后分享一个血泪教训某国企在加固后未更新备份镜像半年后服务器硬件故障从备份恢复的系统仍是加固前的脆弱版本导致新上线服务器直接暴露在互联网。务必在加固完成后立即制作新的系统快照或ISO镜像并标注“SSH加固版-v202406”。这看似琐碎的动作往往决定安全防线的生死存亡。