资讯动态

Linux服务器实战安全加固:账号、引导、登录、端口与弱口令闭环控制

发布时间:2026/10/17 18:35:18 来源:尧图企业网站定制
1. 项目概述这不是教科书里的安全课是我在三台生产服务器上反复摔打出来的实战清单“Linux——系统安全及应用——账号安全控制——系统引导和登录控制——弱口令检测及端口扫描——都是干货——你懂得——”这个标题看着像随手敲出来的碎词堆砌但恰恰是它最真实。我见过太多人把Linux安全当成PPT里的几个名词SELinux、防火墙、密码策略……讲得头头是道一上真机就卡在root密码忘了怎么进单用户模式或者扫出22端口开着却不知道sshd_config里哪一行才是真正决定谁有资格敲回车的命门。这根本不是理论题是生存题。我用这个标题串起的整套动作在某高校数据中心、某物联网设备厂商的边缘网关集群、以及一个小型SaaS服务后台三类完全不同的环境里跑过至少17轮。不是为了“加固”而是因为某次凌晨三点告警一台对外提供API的CentOS 7服务器被横向渗透攻击者没动代码只改了/etc/passwd里一个UID为0的隐藏账户然后用这个账户反向SSH连回内网数据库服务器——整个过程没触发任何IDS规则因为所有操作都走的是合法shell通道。事后复盘问题不在漏洞而在基础控制链的断裂引导阶段没设GRUB密码登录阶段没限制tty会话密码策略形同虚设而端口扫描工具扫出的开放端口列表居然没人对照着服务配置逐条验证权限收敛程度。所以这篇内容不讲“什么是PAM”不画“安全模型金字塔”只告诉你当你的服务器已经在线运行你只有30分钟窗口期该按什么顺序、用哪几条命令、改哪几个文件、验证哪几个关键点才能把最可能被利用的入口堵死。核心关键词——账号安全控制、系统引导控制、登录控制、弱口令检测、端口扫描——每一个都不是孤立模块而是环环相扣的锁链。比如你设了强密码策略但如果GRUB没有密码攻击者重启进单用户模式就能直接passwd -d root清空密码你禁用了root远程登录但如果/etc/ssh/sshd_config里PermitEmptyPasswords yes还开着一个空密码账户就能绕过所有限制你扫出了8080端口开放但如果不检查netstat -tulnp | grep :8080背后是哪个进程、该进程以哪个用户身份运行、该用户是否拥有不必要的sudo权限那扫描结果就是一张废纸。适合谁看运维工程师、DevOps人员、刚接手线上服务的开发同学甚至是有自建NAS或家用服务器的爱好者。不需要你背熟所有参数但必须清楚每一步操作在系统底层触发了什么机制——比如usermod -L锁账户本质是往shadow密码字段前加!而usermod -s /sbin/nologin则是改shell路径两者防爆破效果差一个数量级再比如systemctl mask gettytty1.service和systemctl disable gettytty1.service前者是物理性删除符号链接后者只是取消开机启动重启后tty1依然能被暴力尝试。这些细节决定了你是在修墙还是在墙上画砖。2. 账号安全控制从创建到锁定每一步都在对抗自动化脚本2.1 创建账户时的“第一道防线”别让默认配置成为后门很多人创建新用户只敲useradd username这埋下了第一个雷。默认情况下useradd会做几件危险的事给用户分配一个可登录的shell通常是/bin/bash不设置密码过期时间不限制密码重用次数甚至可能分配一个UID在1000以下的“系统账户范围”某些发行版默认行为。攻击者拿到一个低权限账户第一件事就是查/etc/passwd找UID1000且shell不是/sbin/nologin的账户这类账户往往被遗忘、权限松散是提权跳板。我现在的标准操作是useradd -m -s /bin/bash -c WebApp Service Account -U -K UID_MIN10000 -K UID_MAX60000 webapp拆解一下每个参数的实战意义-m强制创建家目录避免后续手动mkdir权限混乱-s /bin/bash明确指定shell不依赖发行版默认有些精简版默认是/bin/sh功能受限-c添加注释方便后期审计时一眼识别账户用途-U自动创建同名用户组避免usermod -aG漏加-K UID_MIN10000 -K UID_MAX60000这是关键覆盖系统默认的UID范围通常0-999为系统账户1000为普通用户把业务账户UID严格限定在10000-60000之间。为什么因为很多提权EXP会遍历/etc/passwd中UID1000的账户试图利用其遗留的sudoers配置或SUID二进制文件。把业务账户UID拉高等于在攻击者扫描列表里主动隐身。提示-K参数需要/etc/login.defs中USERGROUPS_ENAB yes开启否则-U无效。执行前先grep USERGROUPS_ENAB /etc/login.defs确认。2.2 密码策略不是越复杂越好而是要让爆破成本高于收益“密码必须包含大小写字母、数字、特殊字符长度≥12位90天强制更换”——这套策略在桌面环境合理但在服务器上可能是灾难。我见过某金融客户因密码策略太严运维人员为记住密码在/root/.bash_history里明文记录passwd命令和新密码反而制造更大风险。真正的密码安全核心是增加攻击者的时间成本和失败率而非单纯提高记忆难度。我的实践方案分三层第一层PAM模块硬约束防弱口令编辑/etc/pam.d/common-passwordDebian/Ubuntu或/etc/pam.d/system-authRHEL/CentOS在password [success1 defaultignore] pam_unix.so行上方插入password requisite pam_pwquality.so retry3 minlen10 difok3 maxrepeat2 reject_username enforce_for_root参数详解retry3输错3次密码后退出防止脚本连续试探minlen10最低10位比12位更务实兼顾安全与可用性difok3新密码必须与旧密码至少3个字符不同防“Password1→Password2”式简单递增maxrepeat2禁止同一字符连续出现3次如aaa大幅降低字典生成效率reject_username禁止密码包含用户名堵死最常见弱口令enforce_for_rootroot账户也强制执行避免最高权限账户成短板。第二层密码生命周期管理防长期未更新用chage命令精准控制chage -M 90 -m 7 -W 7 -I 30 webapp-M 90密码最长使用90天-m 7密码最短使用7天防刚改完立刻再改-W 7到期前7天开始每天登录时提醒-I 30过期后30天内未改密码账户自动锁定注意不是禁用是锁定仍可被sudo启用。注意chage -l username可查看当前策略chage -d 0 username可强制用户下次登录时修改密码适用于新员工入职场景。第三层SSH密钥替代密码根除密码传输风险这是最有效的弱口令防御。在客户端生成密钥对ssh-keygen -t ed25519 -C webapp-deploycompany.com -f ~/.ssh/webapp_deployed25519算法比RSA更安全、更快且密钥更短。将公钥部署到服务器ssh-copy-id -i ~/.ssh/webapp_deploy.pub -p 2222 webappserver_ip关键配置/etc/ssh/sshd_configPubkeyAuthentication yes PasswordAuthentication no # 彻底关闭密码登录 PermitEmptyPasswords no重启SSHsystemctl restart sshd。此时webapp账户只能用密钥登录即使密码是123456也毫无意义。2.3 账户锁定与禁用理解-L、-s、-e的本质区别很多教程说“用usermod -L username锁账户”但没说清-L只是在/etc/shadow密码字段前加!而passwd -l username效果相同。攻击者只要知道/etc/shadow路径用sed -i s/^username:!.*$/username:$6$... /etc/shadow就能暴力替换回一个有效哈希——前提是他们已有root权限。所以-L本质是防未授权的正常登录不是防root下的恶意篡改。真正需要区分的三种状态操作命令/etc/passwd变化/etc/shadow变化实际效果适用场景usermod -s /sbin/nologin usernameshell字段改为/sbin/nologin无变化用户可登录但立即被nologin程序退出无法获得shell服务账户如nginx、mysql需系统调用但不应交互登录usermod -L username无变化密码字段前加!如$6$...→!$6$...密码验证永远失败但账户仍可被其他认证方式如SSH密钥使用临时停用人工账户保留密钥登录权限usermod -e 2025-01-01 username无变化expire字段设为日期到期后任何认证方式均失败外包人员、实习生等有明确服务期限的账户我处理服务账户的黄金组合是usermod -s /sbin/nologin -L -e 2099-12-31 nginx既禁用交互shell又锁定密码防意外启用还设超长有效期避免到期自动失效影响服务。实操心得usermod -s /bin/false和/sbin/nologin效果类似但/sbin/nologin会向用户显示友好提示如“This account is currently not available”而/bin/false静默退出不利于排查。优先选/sbin/nologin。3. 系统引导与登录控制守住重启后的第一道门3.1 GRUB引导菜单加密让物理接触不再等于root权限服务器被拖走硬盘概率低。但机房管理员误操作、外包人员调试时重启进单用户模式非常现实。GRUB密码是防止此类事件的最后屏障。重点不是“设密码”而是确保密码生效且无法被绕过。RHEL/CentOS 7 和 Debian 11 的GRUB2配置逻辑不同我以CentOS 7为例第一步生成加密密码不要用明文用grub2-mkpasswd-pbkdf2生成PBKDF2哈希grub2-mkpasswd-pbkdf2 # 输入密码后得到类似pbkdf2.sha512.10000.1234567890ABCDEF...第二步编辑GRUB配置修改/etc/grub.d/40_custom在末尾添加set superusersadmin password_pbkdf2 admin pbkdf2.sha512.10000.1234567890ABCDEF...注意admin是超级用户名称可自定义password_pbkdf2后跟用户名和哈希值。第三步重建GRUB配置grub2-mkconfig -o /boot/grub2/grub.cfg关键验证重启服务器在GRUB菜单界面按e编辑启动项如果看到Press c for a command-line但无法输入命令或输入c后提示Authentication required说明成功。若仍能直接编辑检查/boot/grub2/grub.cfg中是否包含set superusers和password_pbkdf2行且/etc/default/grub中GRUB_DISABLE_RECOVERYtrue已设置禁用恢复模式菜单。3.2 单用户模式防护从源头掐断rd.break和init/bin/bashGRUB密码防的是菜单编辑但攻击者仍可能通过内核参数注入绕过。最常见的是在GRUB启动时按e找到linux16或linux行末尾添加rd.breakRHEL或init/bin/bashDebian从而在init阶段获得root shell。防护方案分两步1. 锁定内核参数GRUB级在/etc/grub.d/40_custom中为每个启动项添加--unrestricted参数的反向限制menuentry CentOS Linux (3.10.0-1160.el7.x86_64) 7 (Core) --unrestricted { ... }--unrestricted表示此菜单项无需认证即可启动但必须配合GRUB超级用户设置。原理是只有认证用户才能看到并选择带--unrestricted的菜单项未认证用户只能看到默认菜单且无法编辑。因此所有非默认菜单项如旧内核、救援模式都应不加--unrestricted使其默认受保护。2. 内核级加固终极防护编辑/etc/default/grub在GRUB_CMDLINE_LINUX中添加GRUB_CMDLINE_LINUX... audit1 lockdownconfidentialityaudit1启用内核审计记录所有特权操作lockdownconfidentiality启用内核锁定模式禁止在运行时修改内核内存、加载未签名模块、修改内核参数包括rd.break。此模式下即使进入单用户模式也无法执行mount -o remount,rw /sysroot等关键操作。更新配置grub2-mkconfig -o /boot/grub2/grub.cfg重启生效。注意lockdownconfidentiality可能影响某些需要动态加载驱动的硬件如某些GPU生产环境启用前务必在测试机验证。3.3 登录控制TTY、SSH、图形界面的三重过滤网登录控制不是“开/关”开关而是分层过滤。我按访问路径梳理TTY终端CtrlAltF1~F6这是最原始的登录入口常被忽略。默认所有6个TTY都启用攻击者可直接在机房键盘上尝试。关闭非必要TTY# 查看当前启用的TTY loginctl list-seats # 禁用tty2-tty6只留tty1 systemctl mask gettytty2.service gettytty3.service gettytty4.service gettytty5.service gettytty6.servicemask比disable更彻底它创建指向/dev/null的符号链接无法被systemctl unmask以外的方式启用。SSH远程登录/etc/ssh/sshd_config是主战场我的最小化安全配置Port 2222 # 非标准端口减少自动化扫描 Protocol 2 # 禁用SSHv1 PermitRootLogin no # 绝对禁止root远程登录 AllowUsers webapp deploy # 只允许指定用户用空格分隔 AllowGroups ssh-users # 或按组控制需提前创建groupadd ssh-users MaxAuthTries 3 # 认证失败3次后断开连接 ClientAliveInterval 300 # 5分钟无活动自动断开防会话劫持 UsePAM yes # 启用PAM使密码策略生效重启生效systemctl restart sshd。图形界面GNOME/KDE若服务器装了桌面环境不推荐但存在需额外控制编辑/etc/gdm3/custom.confGDM3或/etc/lightdm/lightdm.confLightDM设置[daemon] TimedLoginEnablefalse AutomaticLoginEnablefalse禁用图形登录服务systemctl set-default multi-user.target。实操心得AllowUsers和AllowGroups是白名单机制比DenyUsers更安全。曾有个案例运维误将DenyUsers root写成DenyUsers roo导致root账户畅通无阻。4. 弱口令检测与端口扫描从发现到验证的闭环工作流4.1 弱口令检测不用商业工具用Linux原生命令组合拳商业弱口令扫描器如John the Ripper强大但部署复杂、易被误报。我用三步原生命令法10分钟内完成全量检测第一步导出所有账户的密码哈希需rootawk -F: ($2 ! * $2 ! ! $2 ! ) {print $1 : $2} /etc/shadow /tmp/hashes.txt解释$2是密码字段*和!表示账户被锁定或无密码空字符串表示空密码极度危险只导出有效哈希。第二步用hashcat离线爆破本地机执行不上传服务器在本地Linux机器安装hashcat# 下载rockyou.txt字典需自行获取 wget https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt # 爆破-m 1800表示sha512crypt对应大多数现代Linux hashcat -m 1800 -a 0 /tmp/hashes.txt rockyou.txt --force--force忽略NVIDIA驱动警告。爆破结果存于hashcat.potfile用hashcat --show /tmp/hashes.txt查看明文密码。第三步定位高危账户并修复# 找出空密码账户紧急 awk -F: ($2 || $2 !) {print $1} /etc/shadow # 找出密码过期账户可能被遗忘 chage -l $(cut -d: -f1 /etc/shadow | head -10) 2/dev/null | grep -E (Password expires|Account expires) | grep never注意/etc/shadow权限必须是600否则awk读取会失败。检查ls -l /etc/shadow。4.2 端口扫描不只是nmap -sV更要关联服务与权限nmap -sS -p- server_ip能扫出开放端口但真正的风险在于端口背后的服务配置。我的扫描-分析-加固闭环1. 全端口扫描基础发现nmap -sS -T4 -p- --min-rate 1000 -oA full_scan 192.168.1.100-sSTCP SYN扫描隐蔽-T4提速--min-rate 1000每秒至少1000个包加快速度-oA输出为多种格式nmap, gnmap, xml。2. 服务深度分析关键步骤对扫描出的每个开放端口执行# 查看监听进程及用户 ss -tulnp | grep :22 # 输出示例tcp LISTEN 0 128 *:22 *:* users:((sshd,pid1234,fd3),(sshd,pid1235,fd3)) uid:0 # 检查该进程的配置文件 ls -l /etc/ssh/sshd_config # 检查该用户是否有sudo权限 getent group sudo | grep webapp3. 权限收敛验证最终加固根据分析结果制定收敛策略扫描结果风险分析加固操作22/tcp open sshuid:0root用户运行sshd权限过大修改/etc/ssh/sshd_configUsePrivilegeSeparation sandbox启用沙箱User nobody降权运行8080/tcp open httpuid:1000普通用户运行Web服务可能提权用systemd服务文件指定Userwww-data并设置NoNewPrivilegesyes3306/tcp open mysql0.0.0.0:3306MySQL监听所有IP暴露内网修改/etc/my.cnfbind-address 127.0.0.1仅本地访问实操心得ss -tulnp比netstat更快更准且-p参数需root权限普通用户看不到进程名。若ss不可用lsof -i -P -n -sTCP:LISTEN是备选。4.3 自动化巡检脚本把重复劳动变成定时任务把上述检测固化为脚本加入crontab每日执行#!/bin/bash # /usr/local/bin/security-audit.sh DATE$(date %Y%m%d) LOG/var/log/security-audit-$DATE.log echo Security Audit Start $(date) $LOG # 检查空密码 echo Empty password accounts: $LOG awk -F: ($2 || $2 !) {print $1} /etc/shadow $LOG # 检查SSH配置 echo SSH config check: $LOG grep -E ^(PermitRootLogin|PasswordAuthentication|Port) /etc/ssh/sshd_config $LOG # 检查开放端口及进程 echo Listening ports and processes: $LOG ss -tulnp 2/dev/null | grep -E :(22|2222|80|443|3306|5432) $LOG # 发送报告需配置mailx if [ -s $LOG ]; then mailx -s Security Audit Report $DATE admincompany.com $LOG fi加入crontab# 每日凌晨2点执行 0 2 * * * /usr/local/bin/security-audit.sh5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 GRUB密码设了但不起作用检查这四个致命点问题现象重启后GRUB菜单仍可随意编辑无密码提示。排查顺序确认GRUB版本与配置文件位置RHEL/CentOS 7配置在/etc/grub.d/40_custom重建用grub2-mkconfigDebian 11配置在/etc/grub.d/40_custom但重建命令是update-grub若混淆grub2-mkconfig在Debian会报错update-grub在RHEL不存在。检查/boot/grub2/grub.cfg是否包含密码行grep -A5 -B5 password_pbkdf2 /boot/grub2/grub.cfg若无输出说明grub2-mkconfig未正确执行或40_custom语法错误如缺少}。验证/etc/default/grub中GRUB_DISABLE_RECOVERYtrue若为false恢复模式菜单会绕过密码保护。修改后必须grub2-mkconfig。BIOS/UEFI启动模式不匹配Legacy BIOS下配置GRUB2但服务器实际是UEFI启动配置文件路径应为/boot/efi/EFI/redhat/grub.cfg。检查ls /sys/firmware/efi存在则为UEFI。我踩过的坑某次在UEFI服务器上按Legacy流程配置grub2-mkconfig生成的配置在/boot/grub2/但UEFI实际读取/boot/efi/EFI/centos/grub.cfg导致密码失效。解决方案grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg。5.2usermod -L锁账户后为什么SSH密钥还能登录这是经典误解。usermod -L只影响密码认证即/etc/shadow中的密码哈希验证。SSH密钥认证走的是/home/username/.ssh/authorized_keys文件校验与shadow无关。所以usermod -L username→ 密码登录失败密钥登录成功usermod -s /sbin/nologin username→ 密码和密钥登录都会失败因为shell被禁用usermod -e 1970-01-01 username→ 所有认证方式均失败账户过期。验证方法# 锁定账户 usermod -L testuser # 尝试密码登录应失败 ssh testuserlocalhost # 尝试密钥登录应成功 ssh -i ~/.ssh/testuser_key testuserlocalhost5.3nmap扫出端口开放但ss -tulnp看不到进程真相是Docker或容器问题现象nmap -sS localhost显示8080/tcp open http但ss -tulnp | grep 8080无输出。原因Docker容器映射了宿主机端口但进程在容器内运行ss在宿主机视角看不到容器内进程的详细信息。排查# 查看Docker容器端口映射 docker ps --format table {{.ID}}\t{{.Names}}\t{{.Ports}} | grep 8080 # 进入容器检查真实进程 docker exec -it container_id ps aux | grep -E (nginx|apache|java) # 检查容器内用户权限 docker exec -it container_id id -u $(ps aux | grep -E (nginx|apache) | awk {print $1} | head -1)加固Docker运行时加--read-only只读文件系统容器内用非root用户运行服务docker run -u 1001:1001 ...宿主机防火墙限制Docker桥接网络iptables -A FORWARD -i docker0 -o eth0 -j DROP。5.4 弱口令检测时hashcat报错“OpenCL driver not found”用CPU模式救急问题在无GPU的服务器或虚拟机上hashcat因缺少OpenCL驱动无法运行。解决方案强制使用CPU内核hashcat -m 1800 -a 0 --force --opencl-device-types 1 /tmp/hashes.txt rockyou.txt--opencl-device-types 1指定只用CPU类型1跳过GPU类型2--force忽略驱动警告。性能对比CPU模式比GPU慢10-50倍但胜在稳定。对于小规模账户100个仍可在1小时内完成常用字典爆破。最后分享一个小技巧定期用lastb命令检查失败登录lastb | head -20能快速发现暴力破解痕迹。若发现同一IP高频失败立即用iptables -A INPUT -s xxx.xxx.xxx.xxx -j DROP封禁并追查来源。安全不是一劳永逸而是持续狩猎。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑