Go 主机安全面试:Netlink 网络连接与异常外联检测
主机安全岗位经常会问:Agent 怎样发现异常外联、反弹 Shell、扫描器和挖矿通信?eBPF 可以做实时采集,但在一些客户环境里,内核版本、权限和稳定性会限制 eBPF。Netlink 是 Linux 上更常见的系统接口,适合做网络状态巡检、路由变更监听和连接上下文补全。
岗位场景
text
Linux 主机网络状态
-> Netlink 查询连接 / 路由 / 地址
-> 关联 PID / 进程画像 / 用户 / 容器
-> 标准化五元组与连接方向
-> 检测异常外联 / 可疑监听 / 扫描行为
-> 输出可解释告警面试重点不是“背 Netlink API”,而是讲清楚它能拿什么、拿不到什么、如何和进程事件组合,以及 Go Agent 怎样控制性能和误报。
高频面试题
1. Netlink 在 HIDS/EDR 里主要解决什么问题?
简答:Netlink 用来和 Linux 内核交换网络、路由、地址、邻居表等状态信息,适合做网络态势采集和变更监听。
关键知识点:
- Netlink 是内核和用户态通信机制,不是抓包工具。
- 常见用途包括读取网卡地址、路由表、连接跟踪、邻居表和监听网络变化。
- 对 HIDS 来说,它更适合“状态查询”和“低频监听”,不适合替代完整流量审计。
- 异常外联检测需要把网络状态和进程、用户、命令行关联起来。
Go 落地要点:
- 采集层只负责输出标准化网络事件,不直接写复杂规则。
- 规则层再判断公网外联、可疑端口、异常监听、短时间大量连接等行为。
- 不要为一个小 Agent 自己手写 Netlink 协议栈;优先复用已有稳定库或系统接口。
2. Netlink、procfs 和 eBPF 在网络检测里怎么分工?
简答:eBPF 偏实时事件,procfs 偏进程快照,Netlink 偏网络状态和内核网络对象查询。
| 能力 | 适合做什么 | 主要短板 |
|---|---|---|
| eBPF | 捕获 connect、accept、send 等实时事件 | 部署权限和内核兼容性更敏感 |
| procfs | 关联 PID、fd、cmdline、exe | 容易漏掉短生命周期连接 |
| Netlink | 查询地址、路由、邻居、连接状态 | 进程归因通常还要补其他来源 |
Go 落地要点:
- 低权限或兼容性优先时,可以用 Netlink/procfs 做基础网络巡检。
- 已有 eBPF 事件时,用 Netlink 补路由、网卡、地址族和网络命名空间信息。
- 最终统一成一份
NetworkEvent,避免不同采集源各写一套规则。
3. 如何判断一条网络连接是不是异常外联?
简答:不能只看远端 IP,要结合进程、父进程、用户、端口、资产角色、连接频率和历史基线。
关键知识点:
- Web 进程外联到非常规公网端口,风险高于业务进程访问固定 API。
bash、sh、python、perl、php等解释器直接外联,需要提高风险分。- 内网横向扫描通常表现为短时间多目标、多端口、失败率高。
- 云主机里 metadata 地址、DNS、NTP、软件源访问需要单独建基线,避免误报。
Go 落地要点:
- 事件字段至少包含
host_id、pid、process_path、cmdline、uid、local_addr、remote_addr、remote_port、state。 - 外联判断先做私网/公网分类,再进入规则评分。
- 规则输出证据,不只输出“命中异常外联”。
go
func isPrivateIPv4(ip net.IP) bool {
ip = ip.To4()
if ip == nil {
return false
}
return ip[0] == 10 ||
(ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) ||
(ip[0] == 192 && ip[1] == 168)
}4. 连接如何关联到具体进程?
简答:网络状态通常只有 socket 或五元组,落到告警时还要通过 socket inode、PID、fd 和进程快照做关联。
关键知识点:
/proc/<pid>/fd里能看到socket:[inode]。/proc/net/tcp、/proc/net/udp或 Netlink 返回的 socket 信息可以和 inode 建关系。- PID 可能复用,进程也可能在关联前退出。
- 容器场景要注意网络命名空间,宿主机视角和容器视角不一定一致。
Go 落地要点:
- 关联失败要保留网络事件,不要直接丢弃。
- 进程快照要带采集时间和启动时间,避免 PID 复用误归因。
- 先做低成本关联,命中可疑连接后再补高成本字段,例如
cmdline、exe、cwd。
5. 如何检测反弹 Shell 的网络行为?
简答:看 Web/服务进程拉起解释器,解释器持有公网外联 socket,并且命令行或交互特征可疑。
关键知识点:
- 典型链路:
nginx/php-fpm/tomcat -> sh/bash/python/perl -> 外联 IP:port。 - 反弹 Shell 不一定使用高危端口,443、53、8080 也可能被滥用。
- 单条连接不能直接定罪,需要父进程、用户、cwd、tty、cmdline、连接目标一起判断。
- 攻击者可能用
curl、wget、nc、socat、openssl建链。
Go 落地要点:
- 用小规则表达组合证据:可疑父进程 + 可疑子进程 + 公网外联。
- 给每个命中条件记录
RiskHints,便于告警解释和客户复盘。 - 同一进程短时间重复外联可以做窗口聚合,避免告警刷屏。
6. Netlink 采集如何控制性能开销?
简答:控制扫描周期、限制返回字段、做增量缓存,并把昂贵的进程归因放到可疑连接之后。
关键知识点:
- 全量网络状态巡检成本和连接数相关,高连接主机不能高频扫。
- 连接状态变化快,采集太慢会漏,采集太快会增加 CPU 和锁竞争。
- 路由、网卡、地址这类稳定字段可以缓存。
- 连接归因和命令行读取属于相对慢路径。
Go 落地要点:
- 主循环用
context.Context控制单轮预算。 - 对连接表做轻量去重,只处理新增或状态变化的连接。
- 采集队列满时优先丢低风险重复状态,不阻塞 Agent 核心任务。
7. 如何降低异常外联检测的误报?
简答:用资产角色和历史基线约束规则,不要把所有公网连接都打成高危。
关键知识点:
- 构建服务器、代理服务器、爬虫任务天然会产生大量外联。
- 安全扫描器、运维脚本和备份任务可能和攻击工具行为相似。
- 白名单要精确到进程路径、签名、哈希、用户、目标域名或固定网段。
- 告警应保留命中原因,方便回放和调参。
Go 落地要点:
- 先给规则加风险分,而不是直接二值告警。
- 对固定业务外联建立 allowlist,但要设置过期时间和审计字段。
- 把误报样本做成回归用例,规则调整后跑一遍,防止降噪变成漏报。
学习要点
- Netlink 适合查询 Linux 网络状态和监听网络对象变化,但不能单独完成攻击链还原。
- 异常外联检测要关联进程、用户、父子关系、资产角色和历史基线。
- Go Agent 设计上应把采集、标准化、规则判断分开,避免规则逻辑污染采集层。
- 性能控制优先做扫描预算、缓存稳定字段、可疑后补证据。
小练习
- 设计一个
NetworkEvent结构体,字段覆盖五元组、PID、进程路径、用户、连接状态和证据列表。 - 写一个函数,把 IP 分成公网、私网、本机、链路本地四类,并说明异常外联规则会怎么用。
- 设计规则:
php-fpm -> bash -> 公网外联,列出至少 5 个输出告警时需要展示的证据字段。 - 思考一个误报场景:构建机大量访问公网软件源时,怎样避免被识别为扫描或异常外联?
