ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CentOS 7 SSH暴力破解防护实战:从密码策略到fail2ban的完整加固指南

CentOS 7 SSH暴力破解防护实战:从密码策略到fail2ban的完整加固指南 我刚接手一批 CentOS 7 服务器的时候习惯性翻了翻/var/log/secure结果被其中一台的日志量吓了一跳——光是昨天一天就有四万多次Failed password记录全部是 SSH 端口上的字典爆破尝试。这其实不是什么罕见的场景在公网上放一台默认配置的 CentOS 7半小时之内就会被各类扫描工具问候一轮密码弱一点的机器被攻破只是时间问题。这条博文不打算念 PPT也不做黑客攻防的猎奇展示。我会以 CentOS 7 为对象从密码存储机制、攻击者的破解思路入手把防线一层层搭起来密码策略、PAM 锁定、SSH 加固、fail2ban、权限隔离、审计自查每一步都给出可以直接落地的配置和命令。适合所有正在维护 Linux 服务器、或者刚接手公司 CentOS 7 机器的运维和开发同学参考看完之后你可以直接照着自己服务器做一遍加固。1. CentOS 7 的密码防线到底守在哪里1.1 从 /etc/shadow 看密码的存储逻辑很多新手有个误解觉得 Linux 用户密码存在/etc/passwd里。其实/etc/passwd里的x只是一个占位符真正的密码哈希存放在/etc/shadow文件里。你执行cat /etc/shadow看到的一行记录长这样root:$6$A0B1C2D3E4F5G6H7$h9x...一串很长的字符:18000:0:99999:7:::这串字段按冒号分隔分别代表用户名密码哈希$6$开头代表 SHA-512 算法最后一次修改密码的日期从 1970-01-01 起的天数两次修改密码的最小间隔天数密码有效期天数99999 表示永不过期过期前警告天数宽限期密码过期后还能登录的天数账户失效日期保留字段很多服务器被入侵后root 权限落到攻击者手里第一件事就是读这个文件。因为只要拿到了哈希就可以拖到本地用算力慢慢碰撞。防破解的第一道防线其实就是确保/etc/shadow的权限不被破坏。默认情况下它的权限是000只允许 root 读写你可以用ls -l /etc/shadow确认一下如果看到的不是----------那就已经存在权限配置问题。1.2 为什么哈希算法决定破解成本CentOS 7 默认使用 SHA-512$6$算法。早期 Linux 用过 DES、MD5$1$、SHA-256$5$算法不一样同样的弱密码被破解的速度差别巨大。DES8 位以内、纯字符专用工具每秒能试几十亿次基本等于裸奔MD5可以用 GPU 并行每秒数百亿次朝上也是弱势群体SHA-256/SHA-512计算更重但 GPU 并行后每秒也能到几亿次这里有一笔账如果密码是admin123哪怕用 SHA-512进一个包含几十亿条记录的字典库扫一遍也就几分钟的事。所以结论很直接——哈希算法只能延缓破解速度救不了弱密码真正决定防线强度的还是口令本身的熵值。1.3 弱口令为什么是最大的漏洞无论是从过往的入侵案例还是我自己做过的安全自查来看90% 以上的服务器被拿下的原因不是系统 0day而是弱口令。root/123456、admin/admin、test/test跟业务相关的组合company2020、server123复用办公系统密码员工离职后密码不回收被脱库后倒推攻击者扫描到一台开放 22 端口的 Linux 机器后先跑一轮 Top 100 弱口令字典跑不动就换 Top 1000、Top 10000。成本极低但总有机器会中招。密码爆破防破解的本质就是从密码本身、登录过程、权限隔离三个层面同时加高门槛而不是只依赖某一个工具。2. 攻击者常用的密码破解思路先把套路看穿要防住破解你得先知道对面大概是怎么操作的。这里说的不是教人搞破坏我在做安全审计和授权渗透测试的时候用的也是这些工具和思路了解它们是为了把服务器的短板补上。2.1 在线爆破SSH 端口上的连续试探这是最粗暴也最常见的方式。攻击者拿一个密码字典对目标 IP 的 22 端口反复尝试 SSH 登录工具通常是 hydra、medusa 这类。一条典型的命令长这样仅限你对自己服务器做授权测试时使用hydra -l root -P pass.txt 192.168.1.100 ssh参数含义不复杂-l指定用户名-P指向密码字典最后是目标 IP 和协议。跑起来之后你会在secure日志里看到大量Failed password for root from ...记录。在线爆破的瓶颈是网络延迟和 SSH 握手耗时但攻击者可以用多线程并发一个几千条的字典往往几分钟就能跑完。服务器如果没有任何失败锁定机制爆破成功率完全取决于你的密码强度。2.2 离线破解拿到哈希之后的算力对决比在线爆破更危险的是离线破解。攻击者一旦通过某个漏洞或错误配置拿到了/etc/shadow就脱离了服务器的登录限制环境可以在自己的机器上慢慢算。工具主流是 John the Ripper 和 hashcatJohn the Ripper低调实用小字典、CPU 环境下就能跑hashcatGPU 重型武器多卡并行速度极快拿 hashcat 举例破解一个$6$开头的 shadow 哈希基本流程是先整理哈希文件再指定模式跑字典或者跑掩码hashcat -m 1800 -a 0 shadow_hash.txt rockyou.txt-m 1800对应 sha512crypt-a 0是字典攻击模式。跑的时候 GPU 风扇直接起飞几亿次每秒的速度在弱密码面前就是降维打击。2.3 字典、规则与人的习惯很多人觉得我的密码够复杂了8 位还有大小写和数字那大概率是挡不住带规则的字典攻击的。因为攻击者的字典不是只有简单的密码列表还有各种变异规则比如拿admin做基础词自动生成admin1、admin123、admin!#、Admin123、admin2023、Admin2024、Admin2024这样的变体。这类规则工具里叫 mangling ruleshashcat 和 John 都内置了默认规则集跑一遍的时间远比你想象得短。这里我唯一想强调的经验是密码可读性越强越容易被规则命中。Pssw0rd2024这种看起来很唬人的密码实际在规则字典里早就有了。真正强的密码要么是随机生成的 16 位以上字符串要么是 4 到 5 个随机单词拼接的短语。3. 第一道防线密码策略与 PAM 加固实战3.1 密码复杂度从哪里配置CentOS 7 的密码策略配置分散在两个地方/etc/login.defs控制密码过期周期/etc/pam.d/system-auth和/etc/pam.d/password-auth控制密码复杂度校验规则先看/etc/login.defs里最关键的几项PASS_MAX_DAYS 90 PASS_MIN_DAYS 10 PASS_MIN_LEN 12 PASS_WARN_AGE 7PASS_MAX_DAYS 90密码最长使用 90 天PASS_MIN_DAYS 10设置密码后 10 天内不能修改防止用户立刻改回旧密码PASS_MIN_LEN 12密码最短长度 12 位PASS_WARN_AGE 7过期前 7 天开始提醒但这里有个关键的坑/etc/login.defs只对之后新建的用户生效老用户的密码过期时间还是沿用之前的值。所以改完之后要用chage批量强制存量用户对齐策略chage -M 90 -m 10 -W 7 用户名 chage -l 用户名 # 查看当前用户的密码有效期配置3.2 pam_pwquality拒绝弱密码的真正关卡/etc/login.defs里的PASS_MIN_LEN只能管长度管不了复杂度。真正卡复杂度的是pam_pwquality.so模块。在 CentOS 7 上编辑/etc/security/pwquality.conf核心参数有minlen 14 dcredit -1 ucredit -1 lcredit -1 ocredit -1 difok 5 retry 3参数含义表参数值含义minlen14密码最小 14 位dcredit-1至少包含 1 位数字负数代表最少个数ucredit-1至少包含 1 个大写字母lcredit-1至少包含 1 个小写字母ocredit-1至少包含 1 个特殊字符difok5新密码至少要有 5 个字符与旧密码不同retry3最多允许重试 3 次改完之后需要确认 PAM 配置里真的调用了pwquality。在/etc/pam.d/passwd或system-auth中找到类似这一行password requisite pam_pwquality.so try_first_pass local_users_only retry3 authtok_type如果已经有password requisite pam_pwquality.so字样说明配置生效。这时用passwd修改用户密码设置一个123456系统会直接拒绝。3.3 pam_faillock登录失败自动锁定有了复杂密码还不够如果攻击者对 root 反复尝试虽然密码破不出来但会制造大量日志、占用 SSH 连接资源。这时候需要加登录失败锁定。在 CentOS 7 上推荐用pam_faillock。配置方式在/etc/pam.d/system-auth和/etc/pam.d/password-auth中分别添加在auth段开头添加auth required pam_faillock.so preauth audit silent deny5 unlock_time900 fail_interval900 auth sufficient pam_unix.so nullok try_first_pass auth [defaultdie] pam_faillock.so authfail audit deny5 unlock_time900 fail_interval900在account段添加account required pam_faillock.so参数说明deny5连续失败 5 次锁定unlock_time900锁定 900 秒15 分钟fail_interval900计数窗口 900 秒配置完成后可以故意连续输错 5 次密码再登录会提示账户暂时锁定。这个措施对在线爆破是致命的因为每次锁定 15 分钟爆破效率会呈数量级下降。需要注意的是这个锁定只在当前服务如 SSH维度生效要测试时别把自己锁在机器外面建议先保留一个已登录的会话窗口再验证。4. 第二道防线SSH 远程登录加固4.1 sshd_config 里的高性价比加固项在任何一台 CentOS 7 上SSH 都是远程管理的命脉也是被爆破最集中的入口。/etc/ssh/sshd_config里有几个参数值得马上检查PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes MaxAuthTries 3 LoginGraceTime 20 ClientAliveInterval 300 ClientAliveCountMax 2逐个说下理由PermitRootLogin no禁止 root 直接 SSH 登录管理员先以普通用户登录再su -或sudo -i切换。这样即使攻击者拿到了某个普通用户的密码也还要再过一道 root 密码的坎PasswordAuthentication no禁用密码登录只允许密钥认证直接掐断密码爆破这条路。这一步对网段内有多台互相登服务器需求的场景会有点碍事但对公网服务器来说是必要的MaxAuthTries 3单次连接最多尝试 3 次超过即断开配合MaxSessions限制并发LoginGraceTime 20登录超时时间 20 秒避免大量垃圾连接占据资源改配置之前一定要养成验证的习惯sshd -tsshd -t会检查配置语法不会输出内容就代表语法通过。然后systemctl restart sshd。如果是远程操作别关当前会话新开一个终端测试登录确认新配置没问题再断开旧会话。这个习惯能在关键时刻救你一命。4.2 fail2ban针对暴力破解的主动防御密码认证和 faillock 都是被动防御如果要主动拦截推荐装 fail2ban。它通过分析 SSH 日志检测到失败次数超过阈值就对来源 IP 执行防火墙封禁。CentOS 7 上安装yum install -y epel-release yum install -y fail2ban注意 CentOS 7 需要先装 epel-release 仓库不然找不到fail2ban包。这个细节很多人第一次装时会卡住。配置写在/etc/fail2ban/jail.local[DEFAULT] bantime 3600 findtime 600 maxretry 3 [sshd] enabled true port ssh filter sshd logpath /var/log/secure action firewallcmd-ipset参数说明findtime 600表示 10 分钟内maxretry 3表示失败超过 3 次bantime 3600封禁 1 小时。action firewallcmd-ipset是对应 firewalld 的封禁动作跑了一天后你可以用fail2ban-client status sshd查看当前封禁的 IP 列表。那种连续一个 IP 尝试几百次的记录在 fail2ban 启动后就会被精准拦截。我自己的经验是如果服务器的用户不多maxretry可以设到 2 或 3因为正常用户用密钥登录根本不会失败。设得太宽松反而没有意义。4.3 密钥登录部署与权限细节关闭密码认证的前提是密钥登录已经配置好。按下面的流程部署在本地生成密钥对ssh-keygen -t ed25519 -C your-namecompany把公钥复制到服务器ssh-copy-id -i ~/.ssh/id_ed25519.pub 普通用户服务器IP检查服务器上~/.ssh/authorized_keys的权限chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys权限这个细节特别容易踩坑如果authorized_keys文件权限过大比如 644sshd 会认为文件不安全而直接忽略密钥认证日志里会出现Authentication refused: bad ownership or modes然后你以为是密钥配置问题折腾半天发现是 chmod 没做。如果需要多台服务器管理建议在本地用~/.ssh/config为每台服务器配置Host alias省的每次敲一长串 IP。生产机的私钥文件权限也设为 600不要传到任何一台共享机器上。5. 第三道防线文件权限、账户与权限边界5.1 关键文件权限清单密码攻击不光是靠爆破更多时候是攻击者先拿到一个低权限 shell然后找敏感文件的读取权限。CentOS 7 上这几个文件的权限值得重点确认ls -l /etc/shadow ls -l /etc/passwd ls -l /etc/sshd_config正常状态下文件正确权限风险说明/etc/shadow000 或 600 root:root普通用户不可读防止离线破解/etc/passwd644 root:root需要可读但里面不应存哈希/etc/ssh/sshd_config600 root:root防止普通用户读取配置中的认证细节/etc/sudoers440 root:root普通用户不可写还要排查是否存在被改写权限的情况find / -xdev -type f -perm -002 ! -path /proc/* ! -path /sys/* 2/dev/null这条命令能找出所有其他用户可写的普通文件。如果发现/etc/passwd或某个脚本文件可写就是黑客留下后门的潜在位置。5.2 账户层面的检查与清理很多 CentOS 7 服务器上大量账户是从安装起就没用过的东西games、ftp、nobody这些是系统账户不能乱删但可以设置不可登录而一些之前同事创建的临时账户离职后可能从未被锁掉。检查哪些账户有可登录的 shellawk -F: $7 ~ /bash|sh/ {print $1, $3} /etc/passwd看 UID 为 0 的账户awk -F: $3 0 {print $1} /etc/passwdUID 0 代表超级用户权限正常情况下只有root一个如果出现test、temp这类名字说明系统已经被留了后门账户。对于不用的账户立即锁定passwd -l 用户名锁定后这个账户无法用密码登录但su -到该账户的已有会话还能继续。如果服务器上有多个系统账户都开着 bash能清理到最小化就尽量最小化。5.3 sudo 权限的精细管控密码破解的最终目的多半是提到 root 权限sudo 配置就是提权的开关。使用visudo编辑/etc/sudoers以下几点值得注意不要给普通用户配置NOPASSWD: ALL这意味着任何拿到该用户密码的人直接就是 root使用%wheel组管理 sudo 权限而不是逐个加用户到 sudoers给运维用户尽量限定可执行的命令比如deploy ALL(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx这样即使deploy账户被攻破攻击者也只能重启和查看 nginx拿不到 shell 也改不了系统配置。我之前遇到过一个场景开发提了个需求希望jenkins用户能免密重启 Docker 服务结果给出的配置是jenkins ALL(ALL) NOPASSWD: /usr/bin/docker。看起来只是可以执行 docker但熟悉 Docker 的人都知道docker exec和docker run -v /:/host都是可以变相拿到 root shell 的方式。所以在 sudoers 里给执行权限一定要想到命令本身是否存在逃逸路径。6. 防线效果验证从日志审计到安全自查清单6.1 从日志看攻击痕迹不管配置做得多完善都要定期翻日志。CentOS 7 上 SSH 相关的核心日志在/var/log/secure。看所有失败登录grep Failed password /var/log/secure | tail -20看成功的非正常时间登录grep Accepted password /var/log/secure看成功登录过的用户和来源 IP 排行grep Accepted /var/log/secure | awk {print $9, $11} | sort | uniq -c | sort -nr | head如果发现有某个不认识的 IP 成功登录过或者某个测试账号在凌晨三点有Accepted password基本上可以判定是已经被破掉了。下一步应该是立即断网、保存日志、检查定时任务和启动项里有没有可疑后门这一步之后再看是否需要重装系统。6.2 用暴力破解工具做自我验证时的注意点我在搭建完上面的防线后通常会做一次自我验证用 hydra 对本地服务器的 SSH 跑一轮字典确认防线确实生效。有几个实操上的注意点一定要选在低峰期做避免影响正常用户先确认 fail2ban 已经运行否则你自己跑字典的时候把maxretry触发后封禁的是自己测试机的 IP跑之前观察findtime窗口和maxretry的配合比如findtime600、maxretry3意味着 10 分钟内 3 次失败就会封禁你测试工具的并发线程数不要设置太高否则 1 秒内失败 5 次机器直接把你自己的来源 IP 封了验证完成后查看 fail2ban 状态解除测试封禁fail2ban-client set sshd unbanip 192.168.1.100整个验证流程的目的不是让你去攻击别人的机器而是确认你自己的防线在真实爆破面前确实能顶住。如果一轮测试下来发现某个用户名可以被暴力猜中那说明密码策略还有漏洞。6.3 日常自查清单最后整理一份我每次接手新服务器都会过一遍的清单可以直接抄下来当脚本用密码策略/etc/login.defs和pwquality.conf已检查存量用户chage已更新PAM 锁定pam_faillock已配置deny5锁定时间 15 分钟SSH 配置PermitRootLogin no、PasswordAuthentication no、MaxAuthTries 3已用sshd -t验证fail2ban服务运行中fail2ban-client status sshd能看到被拦截的 IP关键文件权限/etc/shadow为 000/etc/ssh/sshd_config为 600不存在其他用户可写的敏感文件账户审计UID 0 只有 root普通账户 shell 不是 bash 的都已禁用不用的账户全部passwd -l日志检查最近 30 天没有异常的Accepted password补丁更新yum update -y定期执行特别是 openssh 的更新要优先每次做完这一套我才会放心把机器交给业务去跑。安全不是说装了一个工具就完事它本质上是一个持续的流程你看日志的频率、配置审查的频率比任何单点方案都重要。只要攻击者的成本高过了这台机器的价值他们就会去挑更软的柿子捏而你做好这些基础加固就已经比绝大多数服务器硬了。
返回列表