Go 主机安全面试:SSH 登录爆破与账号异常检测
SSH 登录、账号切换和 sudo 提权是 Linux 主机安全里最常见的攻击入口之一。面试里不会只问“怎么看 auth.log”,还会追问:失败登录怎么聚合、成功登录怎么判异常、如何降低运维误报、Go Agent 怎么稳定采集和上报。
岗位场景
text
Linux 登录链路
-> sshd / PAM / sudo / su 产生日志
-> Agent 采集 auth.log、journald 或 audit 事件
-> 标准化账号、来源 IP、登录结果、TTY、命令
-> 时间窗口聚合失败次数与成功登录
-> 关联 sudo、进程执行和网络外联
-> 输出可解释的账号风险告警这类检测的重点不是“失败次数超过阈值就告警”,而是把登录结果、账号基线、来源信誉和登录后的行为放在一起看。
高频面试题
1. SSH 爆破检测应该看哪些字段?
简答:至少看账号、来源 IP、登录结果、时间、认证方式、目标主机和客户端信息。
关键知识点:
- 失败登录要区分账号不存在、密码错误、公钥失败、PAM 拒绝。
- 成功登录要记录来源 IP、用户、时间、TTY、会话 ID。
- 同一来源 IP 爆破多个账号,和同一账号被多个 IP 尝试,是两类不同风险。
- NAT、堡垒机和运维跳板机会让来源 IP 看起来集中,不能只靠 IP 下结论。
Go 落地思路:
- 定义统一事件结构,例如
LoginEvent{User, SrcIP, Result, Method, Time, Host}。 - 对日志采集层只做解析和标准化,检测层再做窗口统计,避免解析逻辑和规则耦合。
- 对
SrcIP + User、SrcIP、User分别维护滑动窗口计数。
2. 为什么不能只用“失败 5 次”判断爆破?
简答:固定阈值容易误报运维输错密码,也容易漏掉低频慢速爆破。
关键知识点:
- 运维人员可能短时间内输错多次,但来源、账号和时间通常稳定。
- 攻击者可能慢速尝试,每分钟只试一两次来绕过固定阈值。
- 分布式爆破会把失败次数打散到多个来源 IP。
- 真正高风险的是“失败尝试后紧跟成功登录”,尤其是陌生 IP 或非常用账号。
Go 落地思路:
- 用多个窗口组合:1 分钟看突发,10 分钟看持续,24 小时看慢速。
- 计数维度不要只放一个 map;至少拆成
bySrcIP、byUser、byPair。 - 窗口状态设置过期清理,避免 Agent 长时间运行后内存增长。
go
type LoginKey struct {
User string
SrcIP string
}3. 成功登录为什么也要检测?
简答:攻击者最终目标不是失败登录,而是拿到可用会话;成功登录后的行为更能说明是否入侵。
关键知识点:
- 陌生地区、陌生 ASN、非常用时间、非常用账号成功登录都值得关注。
- 爆破失败后同一 IP 成功登录,风险高于单独的成功登录。
- 成功登录后立即执行
whoami、id、uname -a、curl、wget、bash等命令,可能是攻击探测。 - root 直接登录、禁用账号登录、系统账号交互登录通常风险更高。
Go 落地思路:
- 登录事件要和进程事件用
uid、session id、tty、时间窗口关联。 - 对成功登录生成短期上下文,后续进程执行可补充
login_user、src_ip字段。 - 服务端可以维护账号基线,Agent 侧只保留必要的近期上下文。
4. auth.log、journald 和 auditd 采集有什么区别?
简答:auth.log 最容易接入,journald 覆盖 systemd 环境,auditd 证据更强但部署和权限成本更高。
关键知识点:
/var/log/auth.log或/var/log/secure适合快速兼容,但日志格式随发行版变化。- journald 可以按 unit、priority、cursor 增量读取,适合 systemd 主机。
- auditd 能记录更细的认证、账号和命令事件,但客户环境未必开启。
- 日志轮转、时钟漂移、权限不足都会导致采集缺口。
Go 落地思路:
- 采集器只承诺 best effort,并上报采集方式、offset、cursor、错误计数。
- 文件日志要处理 rotate:inode 变化后重新打开,不重复上传旧内容。
- 解析失败的样本保留少量计数和脱敏样例,方便线上排障。
5. 如何降低 SSH 登录检测的误报?
简答:用资产角色、账号类型、来源基线和后续行为做分层,而不是一条规则打所有机器。
关键知识点:
- 运维跳板机、CI/CD 机器、测试环境和生产数据库主机的登录模式不同。
- 白名单不能只按 IP 写死,最好带上账号、资产组、时间段和过期时间。
- 只告警“失败很多次”价值有限,关联成功登录、sudo、敏感命令后更可解释。
- 告警里要展示证据:失败次数、涉及账号、来源、首次/末次时间、是否成功。
Go 落地思路:
- 规则输出风险等级:扫描、爆破、疑似成功入侵分开。
- 白名单匹配放在告警生成前,保留命中统计,避免规则被静默绕空。
- 用结构化字段生成告警说明,不在代码里拼一大段不可维护的字符串。
6. Go Agent 如何处理日志高峰和弱网?
简答:采集、解析、检测和上报要解耦,用有界队列和降级策略保护主机资源。
关键知识点:
- 爆破时日志会突然增多,如果同步上报,网络慢会反压采集线程。
- 队列无限增长会吃内存,落盘无限增长会吃磁盘。
- 低价值重复失败事件可以聚合,高价值成功登录和提权事件优先保留。
- 弱网下要记录丢弃数量和降级原因,否则客户问题无法复盘。
Go 落地思路:
- 采集 goroutine 只读日志并投递到有界 channel。
- 解析失败、队列满、上报失败都计数,定期随心跳上报。
- 批量上报时做幂等 ID,避免重试导致服务端重复计数。
7. 面试官问“怎么证明规则有效”时怎么回答?
简答:用白盒样本、历史日志回放和线上灰度指标证明,而不是只说规则逻辑合理。
关键知识点:
- 白盒样本覆盖:错误密码、无效账号、公钥失败、爆破后成功、sudo 提权。
- 回放历史日志看命中量、误报样本和漏报样本。
- 灰度阶段关注告警量、去重率、白名单命中率、解析失败率和 Agent 资源。
- 客户反馈要能反查原始证据和规则版本。
Go 落地思路:
- 把解析器写成纯函数,方便用样例日志做单元测试。
- 检测规则支持离线回放同一批
LoginEvent,线上和离线逻辑保持一致。 - 告警带规则版本、窗口参数和关键证据,便于复盘。
学习要点
- SSH 登录检测要同时看失败、成功和登录后的行为。
- 固定阈值只能作为基础规则,真实系统需要窗口、基线和上下文关联。
- Go Agent 要把采集、解析、检测、上报拆清楚,避免一个环节慢拖垮全链路。
- 降低误报的关键是资产角色、账号类型、来源基线和证据解释。
- 规则有效性要靠样本、回放、灰度和线上指标闭环验证。
小练习
- 设计一个
LoginEvent结构,要求能同时表达 SSH 成功、失败和 sudo 行为。 - 给定 10 分钟内的登录事件,写出你会维护的三个统计 key。
- 如果客户说“堡垒机触发大量爆破告警”,你会先看哪些字段?
- 如何把“失败多次后成功登录”关联到后续的可疑命令执行?
- 如果日志 rotate 后出现重复告警,Go 采集器应该检查哪些状态?
