CalcGuide · 技术博客主页 / 一页纸学习计划
🟡

账号、认证与 SSH 加固:把好第一道门

分类:安全与可靠性 · 路径:docs/topics/identity-and-ssh/README.md

#linux#pam#ssh#sudoers#mfa

从账号、密码策略、登录锁定到 SSH 密钥 + sshd_config 加固 + MFA,让远程接入不留明文

父主题

Linux 系统安全加固:从账号权限到纵深防御

子主题(0)

账号、认证与 SSH 加固:把好第一道门

0. 元信息

1. 学习路线

账号生命周期(usermod/usermod/usermod、UID 范围、shell、nologin)
  → /etc/passwd 与 /etc/shadow 结构(7+9 字段)
  → PAM 框架(auth/account/session/password 四类)
  → pam_pwquality(密码复杂度)+ pam_faillock(失败锁定)
  → wheel + sudoers(受限提权)
  → SSH 协议与密钥(ed25519 / RSA 4096 / ssh-agent)
  → sshd_config 关键指令(认证、登录、转发、Tunnel)
  → SSH 高级(Banner / ChrootDirectory / ForceCommand / Match)
  → MFA:Google Authenticator / YubiKey(可选)

按”先关闭弱门,再限制强门”的顺序:先关 root 直登、密码登录、telnet;再限制能用 SSH 进的人、能做的事、能转发的端口。

2. 阶段周数分配(1~1.5 周,建议 1.5 周)

阶段1 周速通1.5 周稳推备注
1. 账号清理与 usermod0.5 天1 天/usr/sbin/nologin、UID 范围
2. /etc/shadow 与密码哈希0.5 天0.5 天chmod 000 shadow
3. PAM 框架0.5 天0.5 天pam.d 栈顺序
4. pam_pwquality 密码策略0.5 天1 天/etc/security/pwquality.conf
5. pam_faillock 失败锁定0.5 天0.5 天输错 5 次锁 15 分钟
6. sudoers 与 wheel0.5 天0.5 天visudo + sudo -l 验证
7. SSH 密钥(ed25519)0.5 天1 天ssh-copy-id + ssh-agent
8. sshd_config 加固1 天1 天PermitRootLogin no + AllowUsers + MaxAuthTries
9. ForceCommand / ChrootDirectory / MFA1 天1.5 天MFA 可选;先验证 sshd -t

每天 1.5 小时;1 周速通每天 2 小时能跑完,但容易漏 sshd -T 验证与持久化步骤。建议 1.5 周:把 MFA 接入与故障排查(MFA 卡 OTP、AllowUsers 漏掉自己)留时间。

3. 九阶段表

阶段核心知识实践产出可观察学会标准
1. 账号/etc/passwd、UID 0 唯一、/etc/skel、usermod 参数、nologin shell、UID 范围创建一个 opsuser 并禁用 root 直登awk -F: '($3==0) {print}' 只有 root;非活动账号 shell 是 /usr/sbin/nologin
2. shadow 与密码/etc/shadow 字段、密码哈希、chpasswd、passwd -S把 shadow 权限 000;root 之外的密码哈希不可见stat -c %a /etc/shadow = 0;grep root /etc/shadow 仍可由 root 看到
3. PAM 框架pam.d 目录、四类管理、include、substack、control flag(required / requisite / sufficient / optional)画一张 sshd 的 PAM 栈知道每行 pam_xxx.so control 的执行含义
4. 密码策略pam_pwquality + /etc/security/pwquality.confminlen=14 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1新建用户试 7 个 1 的密码被拒;passwd -S user 显示上次设置日期
5. 失败锁定pam_faillock(取代 pam_tally2失败 5 次锁 15 分钟;root 可手动 unlock输错 5 次后 faillock --user <u> 显示锁定;faillock --user <u> --reset 解锁
6. sudoerswheel 组、/etc/sudoers、visudo、%wheel ALL=(ALL) ALLNOPASSWD把 opsuser 加入 wheel;root 用 visudo 校验sudo -l -U opsuser 显示受限规则;非 wheel 用户 sudo 失败
7. SSH 密钥ssh-keygen -t ed25519ssh-copy-idauthorized_keys、ssh-agent、ssh-add、-o 选项用 ed25519 密钥登录成功密钥无密码时仍能登录;私钥权限 600
8. sshd_config 加固PermitRootLogin PasswordAuthentication KbdInteractiveAuthentication ChallengeResponseAuthentication MaxAuthTries LoginGraceTime ClientAliveInterval ClientAliveCountMax AllowUsers X11Forwarding AllowTcpForwarding PermitTunnel Banner改完能密钥登录;密码登录被拒;root 登录被拒sshd -T 输出与配置一致;ssh -o PreferredAuthentications=password user@host 失败
9. SSH 高级与 MFAChrootDirectory ForceCommand Match 块、ForceCommand internal-sftp、MFA(Google Authenticator 或 YubiKey FIDO2)用 ForceCommand 限定用户只能跑指定命令;或加 MFA登录后 w 看 bash 不在自己家目录;或第一次密码 + 第二次 OTP

关键陷阱:PAM 改了不重启 sshd;sshd_config 多块覆盖顺序错;关密码登录前没配密钥锁死自己;AllowUsers 把当前用户漏掉;MFA 与 ForceCommand 冲突时记错误日志。

4. 第一周任务(每天 1.5~2 小时)

Day 1 约定:用一台 Ubuntu 22.04 或 RHEL 9.x 虚机/容器,先建快照;记录发行版、内核、sshd 版本:cat /etc/os-releaseuname -rsshd -V。所有改动必须以非 root 用户 + sudo 执行;保留 console 或第二 SSH 会话,避免锁外。

任务当天交付自检命令
Day 1opsuser(UID 1001),禁 root 直登;usermod -m -s /usr/sbin/nologin -u 1001 opsuserpasswd -S opsuser 看状态;awk -F: '($3==0)' /etc/passwd 验证 root 唯一notes/day1.md 含 uid/shell 验证id opsusergrep opsuser /etc/passwdawk -F: '($3==0)' /etc/passwd | wc -l
Day 2解读 /etc/shadow 9 字段;chmod 000 /etc/shadow + 属主 root:shadow;stat -c '%a %U %G' /etc/shadowpasswd -l testuser!passwd -u testuser 解锁shadow 权限清单ls -l /etc/shadowstat -c '%a %U %G' /etc/shadowpasswd -S testuser
Day 3libpam-pwquality;改 /etc/security/pwquality.confminlen=14 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1);passwd opsuser 试 7 个 1 被拒;试 Abcdef!1234 通过pwquality.conf diff + 拒绝/通过证据grep -E 'minlen|credit' /etc/security/pwquality.confpasswd -S opsuser 看最近修改时间
Day 4/etc/pam.d/common-authpam_faillock.so preauth deny=5 unlock_time=900;故意输错 5 次锁 opsuser;faillock --user opsuser 看状态;faillock --user opsuser --reset 解锁;root 验证 resetnotes/faillock.md 含状态截图faillock --user opsuserjournalctl -u sshd --since today | grep -i fail
Day 5usermod -aG wheel opsuservisudo -c 检查后改 /etc/sudoers%wheel ALL=(ALL) ALLsudo -l -U opsuser 验证;非 wheel 用户 sudo 失败sudoers diff + sudo -l 输出groups opsusersudo -l -U opsusersudo -l -U nobody 应被拒
Day 6ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519ssh-copy-id opsuser@host;本机密钥登录成功;chmod 600 ~/.ssh/id_ed25519ssh-agent + ssh-add 试免二次输 passphrasenotes/day6.md 含 ssh-copy-id 输出与登录日志ls -l ~/.ssh/id_ed25519ssh-add -lssh -o PreferredAuthentications=publickey opsuser@localhost echo ok
Day 7项目:在 /etc/ssh/sshd_config.d/99-hardening.conf 写入:PermitRootLogin noPasswordAuthentication noKbdInteractiveAuthentication noMaxAuthTries 3LoginGraceTime 30ClientAliveInterval 300ClientAliveCountMax 2AllowUsers opsuserX11Forwarding noAllowTcpForwarding noPermitTunnel noPermitUserEnvironment noBanner /etc/issue.netUsePAM yesIgnoreRhosts yes/etc/issue.net 写”Authorized access only”;sshd -t && systemctl restart sshdssh -o PreferredAuthentications=password opsuser@localhost 应被拒;ssh opsuser@localhost 密钥登录成功;sshd -T | grep -Ei 'permitroot|passwordauth|maxauth|allowusers|x11forwarding|forwarding' 看最终值一份 99-hardening.conf + sshd 验证输出sudo sshd -T(看生效值)、sudo sshd -t(看配置合法性)、ssh -v opsuser@localhost 2>&1 | grep -i auth(看走 publickey)

Day 7 拆解

步骤 A —— 最小可用(90 分钟)

  1. 备份:sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
  2. 新建 /etc/ssh/sshd_config.d/99-hardening.conf,先放 5 条核心:PermitRootLogin noPasswordAuthentication noMaxAuthTries 3AllowUsers opsuserBanner /etc/issue.net
  3. /etc/issue.netAuthorized access only. All activity is monitored and recorded. Violations will be prosecuted.;
  4. sudo sshd -t && sudo systemctl restart sshd保另一会线
  5. ssh opsuser@localhost 用密钥登录应成功;ssh -o PreferredAuthentications=password opsuser@localhost 应得 Permission denied (publickey)
  6. sudo sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|allowusers|maxauthtries|banner' 验证生效。

步骤 B —— 强化 + 边界(30~45 分钟)

  1. KbdInteractiveAuthentication no ChallengeResponseAuthentication no,与 MFA 协同时不卡 OTP;
  2. LoginGraceTime 30 ClientAliveInterval 300 ClientAliveCountMax 2,挡慢攻击与死连接;
  3. X11Forwarding no AllowTcpForwarding no PermitTunnel no PermitUserEnvironment no UsePAM yes IgnoreRhosts yes
  4. sudo sshd -t && sudo systemctl restart sshd
  5. sudo sshd -T | grep -Ei 'x11forwarding|allowtcpforwarding|permittunnel|permiteenvironment|usepam|ignorerhosts|clientalive' 看每条生效;
  6. ssh -v opsuser@localhost 2>&1 | grep -E 'auth|method' 验证只走 publickey;
  7. AllowUsers 临时删掉 opsuser 重启 sshd,验证自己被拒;再加回去恢复。

5. 阶段通用验收(每一阶段都通过)

  1. 能用 1 张表说出 CIS Benchmark 1.x(账号)与 5.x(SSH)核心控制项;
  2. 改完配置用 visudo -csshd -tfaillock --userpasswd -Sgrep /etc/shadow 看证据,存进 notes/
  3. 制造 1 个对照实验:留 PasswordAuthentication yes → 用 sshpass -p wrongpass ssh opsuser@localhost 攻击可见;改 no → 攻击被 Permission denied (publickey)
  4. 至少 3 组自定义数据:故意输错密码被锁、非 opsuser 试 sudo -l 被拒、私钥 600 vs 644 在 ssh 时表现差异;
  5. 记录变更:每改一个文件在 notes/changes.md 写 1 条(who/when/what/why/CIS 控制项号);
  6. 能修改已有加固清单(删/加一条 sshd 指令并解释影响),而不是只照搬。

6. 最终验收(学完 9 阶段后)

7. 综合项目

首选:写一份 cis-account-ssh.md —— 跑基线(sshd -Tawk -F: '($3==0)' /etc/passwdgrep -L nologin /etc/passwdstat -c '%a' /etc/shadowsudo -l -U opsuser),按 CIS 1.x/5.x 改完,用同一组命令对比前后结果,输出 diff 报告。

要求:

备选:在一台故意”老配置”的机器(如 /etc/ssh/sshd_config 默认 PermitRootLogin prohibit-passwordPasswordAuthentication yes)上接入 Google Authenticator MFA,验证 OTP 第二次验证生效。

任何综合项目都必须包含:

  1. 需求与成功标准(含 CIS 1.x / 5.x 控制项号 + 期望证据命令);
  2. 基线(前)vs 目标(后)差距表;
  3. 配置按层(账号 / PAM / sudoers / sshd / MFA);
  4. 脚本化(scripts/harden-account-ssh.sh + scripts/verify-account-ssh.sh),幂等可重跑;
  5. 正常 + 异常验证(关掉加固 → sshpass 攻击成功;打开 → Permission denied (publickey));
  6. 报告:基线 / 目标 / 结果 / 复盘;
  7. README;
  8. 复盘记录。

本主题贡献(Loop 6-D · linux-hardening / identity-and-ssh)

本主题交付一套”账号 + PAM + sudoers + sshd + MFA”五层加固脚本化包,能直接灌到 RHEL / Ubuntu 双发行版并验证 sshpass 攻击被拦。

3 项核心职责

4 项交付物

  1. 基线 vs 目标差距表:对照 CIS 1.x / 5.x 控制项号,每项配期望证据命令(passwd -S / faillock --user / sshd -T / sudo -ll)。
  2. 账号 / PAM / sudoers 配置三层落档/etc/pam.d/login + /etc/pam.d/sshd + /etc/security/pwquality.conf + /etc/security/faillock.conf + /etc/sudoers + /etc/sudoers.d/
  3. sshd_config + 密钥策略/etc/ssh/sshd_config(含 Match 块)+ 客户端 ed25519 / ecdsa 密钥生成脚本 + 旧 DSA / RSA < 3072 密钥拒绝规则,配 sshd -T 校验。
  4. MFA + 攻击验证脚本scripts/harden-account-ssh.sh(幂等)+ scripts/verify-account-ssh.sh(用 sshpass 暴力验证被拦,Permission denied (publickey)),含 TOTP 第二次验证演示。

3 个验收指标

8. 推荐开源资料(按角色分工,避免堆链接)

阶段角色资料链接用法
1~9PAM / SSH 权威 man pageman pam.d(5)man sshd_config(5)man pam_pwquality(8)man pam_faillock(8)man sudoers(5)https://man7.org/linux/man-pages/字段解释第一站;先 man 后 wiki
1~9CIS 1.x / 5.x 基线CIS Linux Benchmark v3.0.0https://www.cisecurity.org/注册免费账号下载;逐条对照
1~4PAM 配置实例Arch Wiki: PAMhttps://wiki.archlinux.org/title/PAM字段含义;用 pam-auth-update 生成基线
5sshd_config 实战Red Hat Security Guide: SSHhttps://docs.redhat.com/en/documentation/sshd_config 块覆盖顺序;Match
6sudoers 写法Arch Wiki: Sudohttps://wiki.archlinux.org/title/SudoUser_Alias Runas_Alias Cmnd_Alias
7OpenSSH 密钥与 agentOpenSSH Manualhttps://www.openssh.com/manual.htmlssh-keygen / ssh-agent / -o 选项
9MFA 接入Google Authenticator PAMhttps://github.com/google/google-authenticatorlibpam-google-authenticator.socommon-auth
9FIDO2 / YubiKeyssh-keygen -O webauthnhttps://man.openbsd.org/ssh-keygenFIDO2 resident key;硬件密钥
9SSH 高级O’Reilly《SSH The Secure Shell: The Definitive Guide》O’Reilly 出版sshd_config / 密钥 / 隧道系统讲解
全部攻击者视角Hanno Böck《Linux Hardening in Hostile Networks》https://michael-wolf.de/解释 CIS 为什么这么定;攻击者链
全部命令速查Daniel J. Barrett《Linux Pocket Guide》(O’Reilly)O’Reilly 出版ssh / ssh-keygen / passwd 速查
全部中文友好鸟哥《鸟哥的 Linux 私房菜》基础篇出版社公开渠道sshd / PAM / 账号章节中文环境入门

许可证提示:CIS Benchmarks 注册免费账号下载;Google Authenticator Apache-2.0 可直接用;OpenSSH 是 BSD 风格(保留版权即可);Linux-PAM 是 BSD/GPL 双许可。复制 CIS 控制点脚本到生产前先在 staging 跑一遍 —— 默认读思路后自己写

默认使用顺序man page → Arch Wiki / Red Hat Security Guide → CIS Linux Benchmark(注册下载)→ OpenSSH 官方 Manual → MFA 实现(Google Authenticator / YubiKey ssh-keygen -O webauthn)→ 复盘到 notes/retrospective.md

9. 学习资料汇聚(v0.3 自包含)

本节由本计划生成。

9.1 背景与动机

Linux 服务器 90% 的初始攻击面都从”远程登录”开始:SSH 爆破、弱密码、root 直登、空密码账号、泄露的密钥。账号与 SSH 加固是回报率最高的一层:把 80% 的脚本小子挡在门外。

账号层的核心是最小化:root 不直登、密码够长够杂、失败会锁、sudo 受限、用户唯一 UID、可审计的登录历史。SSH 层的核心是拒绝弱认证:只接受密钥、限制来源、限制动作、可见法律告示。

9.2 概念地图

flowchart TB
  PAM[PAM 框架]
  PwQual[pam_pwquality]
  Faillock[pam_faillock]
  Unix[pam_unix]
  Limits[pam_limits]
  Nologin[pam_nologin]
  Sudo[sudoers / wheel]
  Passwd[/etc/passwd / shadow/]
  UserMgr[usermod / usermod / usermod]
  SSH[sshd]
  Key[authorized_keys / ssh-agent]
  Config[sshd_config]
  MFA[Google Authenticator / YubiKey]
  Banner[Banner / Match]

  PAM --> PwQual
  PAM --> Faillock
  PAM --> Unix
  PAM --> Limits
  PAM --> Nologin
  UserMgr --> Passwd
  Sudo --> PAM
  SSH --> Config
  SSH --> Key
  SSH --> MFA
  SSH --> Banner
  Banner --> Chroot[ChrootDirectory / ForceCommand]

关系:账号 → PAM → sshd → 密钥 / MFA。ChrootDirectoryForceCommand 都在 sshd 层作用,把用户活动范围压缩到最小。

9.3 基础知识讲解

9.3.1 主推资料

资料角色评分
man 5 sshd_configsshd 字段权威5
man 5 pam.dPAM 框架5
Arch Wiki: SSH / PAM / Security字段级解释4
Daniel J. Barrett, Linux Pocket Guide速查4
Hanno Böck, Linux Hardening in Hostile Networks攻击者视角4
O’Reilly SSH The Secure Shellsshd 系统讲解4

9.3.2 备查

资料链接
Red Hat: Configuring sudohttps://docs.redhat.com/en/documentation/
Ubuntu: SSH/OpenSSH/Configuringhttps://help.ubuntu.com/
CIS Linux Benchmark 1.x 5.xhttps://www.cisecurity.org/
Google Authenticator PAMhttps://github.com/google/google-authenticator
YubiKey / FIDO2 / ssh-keygen -O webauthnhttps://man.openbsd.org/ssh-keygen
OpenSSH release noteshttps://www.openssh.com/

9.3.3 必查 man pages

9.4 经典问题与经典案例

#问题为什么会重要最简答案 / 证据
1root UID 不唯一多 root 账号 = 提权awk -F: '($3==0) {print}' /etc/passwd 应只 1 行
2shadow 权限非 000任何用户可爆破chmod 000 /etc/shadow;属主 root
3PermitRootLogin yesroot 拿到即最高no;或 prohibit-password
4PasswordAuthentication yes密钥 + 密码共存no
5PermitEmptyPasswords yes空密码登录no
6没配 MaxAuthTries无限次尝试3
7没设 LoginGraceTime慢攻击拖死 sshd30
8ClientAliveInterval 0死连接保留300 / ClientAliveCountMax 2
9AllowUsers 漏掉自己把自己锁外面改前保 console
10X11Forwarding yes 不需要套接字泄露no
11AllowTcpForwarding yes 默认内网穿透no
12PermitTunnel yes用户开 VPNno
13PermitUserEnvironment yes攻击者注环境变量no
14私钥 644 权限私钥被同用户读chmod 600
15私钥放仓库泄露不放;用 ssh-agent
16Banner 没设法律告示缺失/etc/issue.net
17UsePAM nosshd 绕过 PAMyes
18IgnoreRhosts yes 没显式信任 .rhostsyes
19失败 5 次没锁暴力破解无代价pam_faillock
20wheel 空任何用户 sudo只把 opsuser 加进去
21NOPASSWD: ALL物理接触即提权必须输密码;或限定命令
22!/bin/false 写成 !/bin/falseshell 仍能登/usr/sbin/nologin
23旧账号 games news 还在攻击面变大锁或删
24TMOUT 没设空闲 shell 不超时/etc/profileTMOUT=300
25sudo 日志没集中IR 看不到提权记录默认 /var/log/auth.log;转发到 SIEM
26MFA secret 在仓库OTP 失守单独保管 + 备份
27Chroot 路径权限错sshd 拒绝启动chroot 目录属主 root,权限 755
28ForceCommand 与 MFA 冲突卡在 OTP 阶段ForceCommand 在 PAM 后;测试

9.5 学习难点

概念难点

难点为什么会卡突破路径
PAM 控制位 (required/requisite/sufficient/optional)一行失败行为不同pam-auth-update 重建;查 man
shadow 第二字段 !/*/!! 含义锁/未设/锁shadow(5)passwd -l!
sudoers NOPASSWD 顺序后写覆盖前看完整 sudo -l 输出
sshd_config 块覆盖Match 块与全局冲突sshd -T 看最终生效值
ForceCommand 与 Chroot 一起路径相对 chroot路径相对 chroot 根

思维难点

难点为什么会卡突破路径
关密码登录前没配密钥锁自己提前 console / 第二用户
PAM 改了不重启看似不生效重启 sshd;systemctl restart sshd
失败锁 vs IP 封禁faillock 锁用户,fail2ban 锁 IP两者都用,但前者更精确

工程难点

难点为什么会卡突破路径
几百台机器统一 sshd_config手工不可行Ansible / cloud-init / 配置管理
老系统 PAM 结构差异RHEL vs Ubuntu 模块路径不同pam-auth-update 生成基线
MFA 集成TOTP 库 / YubiKey 接入选 Google Authenticator + pam_google_authenticator.so

9.6 技术标准与接口

9.6.1 Entity

名称版本组织状态许可证
OpenSSH9.xOpenBSD 项目活跃BSD
Linux-PAM1.5+linux-pam 项目活跃BSD/GPL 双许可
sudo1.9+Todd Miller 等活跃ISC
pam_pwquality1.4+pwquality 项目活跃BSD/GPL
pam_faillock0.5+Linux PAM活跃BSD/GPL
Google Authenticator PAM1.0+Google维护Apache-2.0
FIDO2 / WebAuthn2FIDO Alliance / W3C现行公开
CIS Linux Benchmark 1.x / 5.xv2.0CIS现行注册免费
POSIX 1003.12017IEEE / The Open Group现行收费 / draft 公开

9.6.2 Scope

9.6.3 Structure

9.6.4 Ecosystem

9.6.5 Depth Tiers

层级能力
L0知道 root / sudo / ssh
L1看得懂一段 sshd_config 和 sudoers
L2能正确配置 sshd 限制策略、加入 MFA
L3能解释 PAM 行为、SSH 攻击向量、sudo 提权限制
L4能为多机集群设计统一登录基线、密钥轮换、应急解锁流程

本计划目标:L3

9.6.6 Source

10. 常见误区

11. 所有知识点分类(统一规则)

  1. 编程语言
  2. 数据结构与算法
  3. 计算机基础
  4. 工程技术
  5. Web 与后端
  6. 前端与客户端
  7. 数据与人工智能
  8. 项目与职业能力
  9. 安全与可靠性

本计划归属:安全与可靠性 主 + 工程技术 辅。


直接依赖(0)

查看知识图谱