在这里插入图片描述

标签:运维安全 Linux Windows 服务器安全 账户管理


背景说明

很多人遇到过这种情况:明明密码是对的,但就是登录不上服务器。

这时候别急着怀疑自己的密码——很可能是服务器上的安全机制在"作怪"。

本文介绍六种常见的导致"登录失败"的安全机制。

前置说明:SSH连接失败分为两个阶段。

  • 握手阶段失败:指纹不匹配、防火墙拦截、端口未开放——这时候根本没机会输入密码。
  • 认证阶段失败:账户锁定、权限错误、SELinux拦截——输入密码后才触发失败。
    本文主要讨论认证阶段的问题,但也会覆盖一些高频的握手阶段问题。

机制一:账户锁定策略(Account Lockout)

是什么

账户锁定策略是一种安全保护机制。当账户在一定时间内输入错误密码达到一定次数后,系统会自动锁定该账户一段时间。

为什么会登录失败

假设你或你的同事在短时间内多次输入错误密码,账户被锁定后,即使输入正确密码也无法登录。

# 查看账户锁定状态(Linux)
# 较新发行版(RHEL 8+/CentOS Stream/Debian 10+)推荐使用
faillock --user 用户名
faillock --show --user 用户名

# 旧版发行版可能需要pam_tally2(如仍可用)
pam_tally2 --user 用户名
# 或
faillog -u 用户名

如何解锁账户

# 解锁账户(Linux)- 现代发行版
faillock --user 用户名 --reset

# 旧版发行版(如仍支持pam_tally2)
pam_tally2 --user 用户名 --reset
# 或
faillog -u 用户名 -r

# 解锁后立即可以登录

Windows账户锁定解决

# 解锁本地账户
net user 用户名 /active:yes

# 解锁域账户(需要AD模块)
Unlock-ADAccount -Identity 用户名

或等待锁定时间过期(通常30分钟)后自动解锁。

Root用户的特殊性

重要盲点:默认情况下,pam_faillock可能不会锁定root账户。

如果普通用户被锁但root仍能登录,说明系统配置了even_deny_root参数,root默认是免疫锁定的。

# 检查root是否也被锁定
faillock --user root --show

# 如果需要让root也受锁定保护,在pam配置中添加 even_deny_root
auth required pam_faillock.so preauth silent deny=3 even_deny_root unlock_time=1800
auth required pam_faillock.so authfail deny=3 even_deny_root unlock_time=1800

管理员配置建议

# RHEL/CentOS 配置 /etc/pam.d/system-auth 或 /etc/pam.d/password-auth
# 启用faillock模块
auth required pam_faillock.so preauth silent deny=3 unlock_time=1800
auth required pam_faillock.so authfail deny=3 unlock_time=1800

# Debian/Ubuntu 配置 /etc/pam.d/common-auth
auth required pam_faillock.so preauth silent deny=3 unlock_time=1800
auth required pam_faillock.so authfail deny=3 unlock_time=1800

# 设置登录失败3次后锁定30分钟(1800秒)

机制二:SSH密钥指纹验证(Host Key Verification)

是什么

SSH客户端首次连接服务器时,会记录服务器的公钥指纹。之后连接时,会验证服务器的指纹是否匹配。

如果服务器重新安装系统、IP地址复用、或被恶意中间人攻击,指纹就会变化,导致连接失败。

为什么会登录失败

# 典型错误信息
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!      @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.

解决方案

方法1:删除旧的指纹记录(客户端操作)

# 删除指定IP的旧指纹
ssh-keygen -R 服务器IP

# 或手动编辑删除
vim ~/.ssh/known_hosts
# 删除对应IP的那一行

方法2:重新获取指纹(谨慎操作)

# 确认是合法服务器后,强制重新记录指纹
ssh-keyscan -H 服务器IP >> ~/.ssh/known_hosts

警告:只有在确认服务器是合法的情况下才执行上述操作。如果是第一次连接新服务器,这是正常现象。


机制三:SELinux或AppArmor安全机制

是什么

SELinux(Security-Enhanced Linux)和AppArmor是Linux内核的安全模块,限制程序访问特定资源。

有时候即使密码正确,SSH服务也可能因为安全策略限制而无法正常工作。

为什么会登录失败

  • SELinux上下文不正确导致SSH无法读取配置
  • AppArmor限制SSH进程访问某些文件
  • 安全模块误判登录行为为攻击

诊断方法

# 查看SELinux状态
getenforce
# 或
sestatus

# 查看SSH相关的SELinux日志
cat /var/log/audit/audit.log | grep ssh

# 查看AppArmor状态(Ubuntu/Debian)
aa-status

# 查看文件的SELinux安全上下文(关键诊断步骤)
ls -Z ~/.ssh/authorized_keys

致命细节:mv 和 cp 的区别

运维老鸟才知道的坑:从别处移动(mv)authorized_keys文件到.ssh目录,会保留原始目录的SELinux上下文,导致SSH无法读取。而复制(cp)则会继承目标目录的上下文。

# 错误做法:mv会保留原始上下文
mv /tmp/authorized_keys ~/.ssh/

# 正确做法:cp会继承目标目录上下文
cp /tmp/authorized_keys ~/.ssh/

# 如果已经用mv了,必须手动修复上下文
restorecon -Rv ~/.ssh

解决方案

SELinux修复:

# 修复SSH目录的SELinux上下文
semanage fcontext -a -t ssh_home_t '/home/用户名/.ssh(/.*)?'
restorecon -Rv ~/.ssh

# 临时关闭SELinux(不推荐用于生产环境)
setenforce 0

# 永久关闭SELinux(需要重启)
# 编辑 /etc/selinux/config
SELINUX=disabled

AppArmor修复:

# 重启AppArmor中的SSH配置文件
apparmor_parser -r /etc/apparmor.d/usr.sbin.sshd

# 临时关闭AppArmor(不推荐)
systemctl stop apparmor

机制四:SSH密钥权限问题

是什么

SSH对密钥文件和目录有严格的权限要求。如果权限配置不正确,SSH会拒绝认证,导致即使密码正确也无法登录。

为什么会登录失败

SSH要求.ssh目录、密钥文件的权限必须正确,否则安全机制会拒绝使用这些文件。

核心盲点:SSH配置默认开启StrictModes yes,会检查用户家目录的权限。如果家目录权限过于开放(如777),SSH同样会拒绝认证。

诊断方法

# 检查.ssh目录和文件的权限
ls -la ~/.ssh/

# 检查家目录权限(关键!)
ls -ld /home/用户名

# 常见错误:家目录权限过于开放
# drwxrwxrwx 5 user user 4096 Jun  1 10:00 /home/user
#      ↑ 权限太开放(应为700或755)

# 检查.ssh目录权限错误
# drwxrwxrwx 3 user user 4096 Jun  1 10:00 .ssh
#      ↑ 权限太开放(应为700)

# 检查文件所有权(StrictModes也会检查)
ls -la ~/.ssh/
# 正常输出:
# -rw------- 1 user user  200 Jun  1 10:00 authorized_keys
#      ↑ 所属用户和组应该是登录用户本人

解决方案

# 修复家目录权限(家目录不能是777)
chmod 700 /home/用户名

# 修复.ssh目录权限(必须为700)
chmod 700 ~/.ssh

# 修复.ssh目录所有权(所属用户必须是本人)
chown -R 用户名:用户名 ~/.ssh

# 修复家目录所有权
chown -R 用户名:用户名 /home/用户名

# 修复authorized_keys文件权限(必须为600)
chmod 600 ~/.ssh/authorized_keys

# 修复私钥文件权限(必须为600)
chmod 600 ~/.ssh/id_rsa

# 修复公钥文件权限(可以为644)
chmod 644 ~/.ssh/id_rsa.pub

# 如果有config配置文件,也需要设置为600
chmod 600 ~/.ssh/config

提示:StrictModes检查顺序是:家目录 → .ssh目录 → authorized_keys文件。任一环节权限不对都会导致认证失败。


机制五:IP白名单/防火墙限制

IP白名单限制

有些服务器配置了IP白名单,只有白名单内的IP才能连接SSH。

# 检查hosts.allow和hosts.deny(仅适用于较旧系统)
cat /etc/hosts.allow | grep ssh
cat /etc/hosts.deny | grep ssh

# 如果有限制,检查当前IP是否在白名单中
# 查看本机公网IP
curl ifconfig.me

现代系统注意:TCP Wrappers(hosts.allow/hosts.deny)在CentOS 8+、RHEL 9+、Ubuntu 22.04+等现代发行版中已逐渐被弃用。对于新系统,应重点检查nftablesfirewalld的富规则。

防火墙限制

# 检查firewalld状态
firewall-cmd --list-all

# 检查UFW状态(Ubuntu)
ufw status

# 检查nftables规则(现代系统)
nft list ruleset | grep ssh

# 检查iptables规则(旧系统)
iptables -L -n | grep ssh

连接被拒vs认证失败的区分

连接被拒(Connection refused):SSH服务未启动或防火墙拦截
       ↓
认证失败(Permission denied):密码/密钥验证被拒

机制六:Shell环境错误

是什么

SSH认证成功(密码或密钥验证通过),但连接瞬间断开(Connection closed)。这种情况下用户已经"通过了验证",但无法建立会话。

为什么会登录失败

最常见的原因:用户默认Shell在/etc/passwd中配置错误——指定的Shell不存在,或者不在/etc/shells白名单中。

诊断方法

# 查看用户的shell配置
cat /etc/passwd | grep 用户名

# 典型错误输出(Shell路径不存在):
# user:x:1000:1000::/home/user:/bin/bashish
#                                      ↑ Shell不存在!

# 检查/etc/shells白名单
cat /etc/shells

# 检查指定Shell是否存在
ls -l /bin/bash

经典场景:/sbin/nologin

另一种常见情况:某些账户(如SFTP专用用户)的Shell被设置为/sbin/nologin/usr/sbin/nologin,以禁止交互式登录。

# 查看用户shell配置
cat /etc/passwd | grep 用户名

# 典型输出:
# sftpuser:x:1001:1001::/home/sftpuser:/sbin/nologin
#                                         ↑ 禁止交互式登录

# 尝试SSH登录时会立即显示:
# This account is currently not available.

解决方案

# 方法1:修改用户默认Shell为合法Shell
usermod -s /bin/bash 用户名

# 方法2:将错误路径的Shell改为正确路径
usermod -s /bin/bash user

# 如果/bin/bash不在/etc/shells中,添加到白名单
echo "/bin/bash" >> /etc/shells

# 如果确实需要禁止登录(仅SFTP等场景),保持 /sbin/nologin 是正确的安全做法

提示:/sbin/nologin是正常的安全配置,不应修改。如果该用户需要SSH登录,才需要将Shell改为/bin/bash等合法Shell。


总结:登录失败排查流程

密码正确但登录失败?
    ↓
检查1:账户是否被锁定?
    ├─ 是 → faillock --user [name] --reset 或等待
    ↓
检查2:家目录权限是否正确(StrictModes)?
    ├─ 否 → chmod 700 /home/[user] && chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
    ↓
检查3:是否是第一次连接或服务器重装了?
    ├─ 是 → ssh-keygen -R [IP] 删除旧指纹
    ↓
检查4:SELinux上下文是否正确?
    ├─ 否 → restorecon -Rv ~/.ssh
    ↓
检查5:IP白名单/防火墙是否限制?
    ├─ 是 → 将IP加入白名单或联系管理员
    ↓
检查6:Shell路径是否正确?
    ├─ 否 → usermod -s /bin/bash [user]

一分钟快速排障指南

现象 可能原因 核心排查命令
连不上,没出密码框 防火墙/指纹改变/端口未开 ssh-keygen -R [IP] / firewall-cmd --list-all
密码对,提示 Permission Denied 账户锁定 faillock --user [name] --show
密码对,提示 Permission Denied 文件权限/SELinux chmod 600 ~/.ssh/* / restorecon -Rv ~/.ssh
认证成功,但瞬间断开 Shell路径错误或为/sbin/nologin cat /etc/passwd | grep [user]
认证成功,但无法使用密钥 父目录权限或所有权 ls -ld /home/[user](不能是777)/ chown -R user:user ~/.ssh
所有都OK,但就是连不上 TCP Wrappers/现代防火墙 nft list ruleset / cat /etc/hosts.deny

遇到登录问题时,记得逐项排查,安全机制是为了保护服务器,不是为难管理员。


你在运维中还遇到过哪些奇怪的登录问题?欢迎在评论区分享。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐