一、背景:内网安全的隐形防线
做运维的朋友有没有过这样的经历:
- 服务器被人登录了,过了一周才发现
- 想查谁什么时候登录过,只能去翻事件查看器,效率极低
- 买了一堆昂贵的安全产品,配置复杂,小团队根本用不起
- 开源方案要么太重(elk 一套下来几个 g),要么太难用
有没有一个轻量、简单、开箱即用的方案?
这就是我做 lanmonitor 的初衷——一个只有几 mb 的小工具,就能让你实时掌握内网所有机器的登录动态。
二、方案选型:为什么是 winlogbeat + c# winforms?
2.1 事件采集:为什么选 winlogbeat?
windows 自带的安全日志其实非常强大,4624(登录成功)、4625(登录失败)这些事件 id 记录了所有登录行为。
但问题是:怎么把这些日志实时收集起来?
我对比了几种方案:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 自己写服务读 eventlog | 简单可控 | 性能差、断点续传麻烦、兼容性差 |
| wmi 远程查询 | 不用装客户端 | 延迟高、不安全、容易断 |
| winlogbeat | 官方出品、性能好、断点续传、稳定可靠 | 需要装客户端 |
最终选择了 winlogbeat——elastic 官方出品的 windows 日志采集器,经过无数生产环境验证,稳定性有保障。
2.2 服务端:为什么用 c# winforms?
既然用了 winlogbeat,它的输出目标一般是 elasticsearch。但我们只是要个告警,没必要搭一套 elk 吧?
思路一转:能不能直接模拟 elasticsearch 的 bulk api,接收 winlogbeat 的数据?
完全可以!
winlogbeat 发的就是标准的 http post 请求,body 是 ndjson 格式。我们只要用 httplistener 监听端口,解析请求,弹窗告警就行了。
为什么用 c# winforms?
- 原生 windows 体验:桌面程序、系统托盘、弹窗告警,体验最好
- 开发效率高:winforms 拖拖控件(或者手写代码)就能出界面
- 部署简单:单 exe,.net 8 自包含发布,不用装运行时
- sqlite 本地存储:零配置,一个文件搞定数据库
三、核心原理:300 行代码模拟 elasticsearch
3.1 整体架构
┌─────────────────┐ http /_bulk ┌─────────────────┐
│ 被监控服务器 │ ──────────────────> │ 监控端电脑 │
│ winlogbeat │ ndjson 格式 │ lanmonitor │
│ (采集安全日志) │ │ (弹窗告警) │
└─────────────────┘ └─────────────────┘
原理非常简单:
- 被监控端装 winlogbeat,配置 output.elasticsearch 指向监控端
- 监控端用 httplistener 监听 9200 端口,模拟 elasticsearch
- 收到登录事件后,解析数据,右下角弹窗告警
- 数据存 sqlite,方便历史查询
3.2 模拟 es bulk api 有多简单?
核心代码其实只有几十行:
private async task listenloop(cancellationtoken token)
{
while (!token.iscancellationrequested && _listener.islistening)
{
var context = await _listener.getcontextasync();
if (path.endswith("/_bulk"))
{
// 解析 ndjson 格式的批量数据
using var reader = new streamreader(context.request.inputstream);
var content = await reader.readtoendasync();
var lines = content.split('\n');
// 第 1 行是 index 元数据,第 2 行是事件数据
for (int i = 0; i < lines.length - 1; i += 2)
{
var eventjson = lines[i + 1];
var evt = jsonserializer.deserialize<winlogbeatevent>(eventjson);
onloginevent?.invoke(evt); // 触发事件,弹窗告警
}
}
// 返回 es 标准响应格式
context.response.statuscode = 200;
var response = "{\"took\":1,\"errors\":false,\"items\":[]}";
await context.response.outputstream.writeasync(encoding.utf8.getbytes(response));
context.response.close();
}
}
就这么简单!winlogbeat 以为数据写入了 elasticsearch,实际上被我们截胡了。
四、功能展示:麻雀虽小,五脏俱全
4.1 实时弹窗告警
有人登录时,右下角立刻弹出告警窗口:
- 红色:登录失败(有人在破解?)
- 橙色:rdp 远程桌面登录
- 蓝色:普通网络登录
弹窗支持置顶、闪烁、声音提醒,想忽略都难。
4.2 多维度搜索筛选
积累了一定数据后,可以按各种维度筛选:
| 筛选维度 | 选项 |
|---|---|
| 关键词 | 主机名 / 用户名 / 来源 ip 模糊搜索 |
| 时间 | 今天 / 昨天 / 近 7 天 / 近 30 天 |
| 事件类型 | 全部 / 登录成功 / 登录失败 |
| 登录类型 | 全部 / rdp / 网络登录 / 其他 |
| 严重程度 | 全部 / 普通 / 警告 / 严重 |
| 读取状态 | 全部 / 未读 / 已读 / 已处理 / 已忽略 |
再也不用去事件查看器里一条条翻了。
4.3 安全加固
企业内网用,安全肯定要考虑:
token 鉴权:支持 x-auth-token 和 authorization bearer 两种格式,没有 token 的请求直接 401 拒绝。
ip 白名单:支持精确 ip、cidr 网段、通配符三种格式,只允许信任的机器推送数据。
两层防护,足够应对一般的内网场景。
4.4 其他贴心功能
- 配置界面化:5 个 tab 页,可视化配置所有参数,不用改代码
- 开机自启:注册表实现,开机自动运行
- 数据自动清理:每小时自动清理过期数据,不用担心数据库越来越大
- 告警去重:短时间内相同的告警自动去重,不会被弹窗淹没
- 全局异常捕获:程序出错也不会崩,记录日志继续运行
- 系统托盘:最小化到托盘,不占任务栏空间
五、部署指南:5 分钟搞定
监控端(你的电脑)
- 下载 lanmonitor 程序,直接运行
- 右键托盘 → 设置,配置 token 和 ip 白名单
- 防火墙放行 9200 端口
被监控端(服务器)
下载 winlogbeat(官方免费)
编辑 winlogbeat.yml:
winlogbeat.event_logs:
- name: security
event_id: 4624, 4625 # 只采集登录成功/失败事件
ignore_older: 24h # 忽略 24 小时前的历史
output.elasticsearch:
hosts: ["http://监控端ip:9200"]
headers:
x-auth-token: "你的token"安装服务,启动

六、扩展方向:不止是登录监控
现在只做了登录事件监控,但 winlogbeat 能采集的远不止这些:
安全相关:
- 账户创建/删除/锁定(4720/4726/4740)
- 密码修改(4723/4724)
- 进程创建(4688)—— 可以做进程白名单
- 服务安装(4697)—— 检测恶意服务
- 防火墙规则变更(4946/4947/4948)
- 日志清除(1102)—— 有人删日志?立刻告警
系统相关:
- 系统启动/关闭(6005/6006)
- 服务状态变化(7036)
- windows 更新(19/20)
进阶玩法:
- 异常登录时间检测(凌晨 3 点登录?)
- 异地登录检测(来源 ip 不在白名单)
- sysmon 集成(更强大的进程/网络/文件监控)
想象空间很大,这只是一个开始。
七、写在最后
做这个项目最大的感受是:很多时候,解决问题不需要复杂的方案,简单的工具反而最实用。
- 不需要 elasticsearch,不需要 kafka,不需要各种高大上的中间件
- 一个 几 mb 的 winforms 程序,加一个官方的 winlogbeat
- 就能解决内网登录监控这个实实在在的痛点
技术不在于多复杂,而在于能不能解决问题。
如果你也有类似的需求,不妨试试这个工具。也欢迎提 issue、pr,一起完善它。
以上就是基于c# winforms编写一个日志监控工具的详细内容,更多关于c#日志监控的资料请关注代码网其它相关文章!
发表评论