gregorwolf1973/ha-guardian
GitHub: gregorwolf1973/ha-guardian
HA Guardian 是一款 Home Assistant 暴力破解防护插件,通过监控多源日志自动封禁恶意登录 IP。
Stars: 2 | Forks: 0
🌐 **English** · [Deutsch](README.de.md)
# HA Guardian
### 在 Guardian 中设置
1. 打开 **Settings 选项卡**
2. 在 **CrowdSec LAPI** 下填写:
- **LAPI URL**:例如 `http://a0d7b816-crowdsec:8080`(CrowdSec addon 的内部 Docker 主机名)
- **Machine ID**:`ha-guardian`(如 `cscli machines add` 中所指定)
- **Password**:所选密码(明文,**非** SHA256 哈希值)
3. 点击 **Test Connection** → 成功后会出现绿色提示
4. 在 **Ban Targets** 下启用 **CrowdSec** 开关
### 工作原理
- 每次自动或手动封禁时,Guardian 都会向 `/v1/alerts` 发送警报,其中包含嵌入的封禁决策
- 每次解封时,该决策将通过 `DELETE /v1/decisions?ip=X.X.X.X` 移除
- 封禁持续时间按 1:1 传递给 CrowdSec(`0` = 永久 → 在 CrowdSec 中为 10 年)
- Guardian 使用带有自动续期功能的 JWT token 作为机器 watcher 进行身份验证
### 在 CrowdSec 中验证封禁
```
cscli decisions list
```
## Addons 选项卡 – 启用哪些日志源?
Addons 选项卡显示所有检测到的日志源,并带有用于启用/禁用每个日志源的开关。
### ⚡ Nginx Proxy Manager – 最重要的来源
**如果您使用 NPM 作为反向代理,请启用此项。**
由于所有 addon 流量都通过 HA 的内部代理(`172.30.32.1`),大多数 addon 的 Docker 日志**不**包含真实的攻击者 IP。NPM 是唯一可以看到真实客户端 IP 的点:
```
[01/Apr/2026:16:04:02 +0200] - 500 500 - POST https 2fa.example.com
"/user/login" [Client 91.42.192.232] ...
↑ real IP here
```
**启用 NPM 日志记录:**
1. NPM Web UI → Settings → Default Site
2. 启用“Access Log”
3. 在 Guardian Addons 选项卡中:启用 `Docker: Nginx Proxy Manager`
### 哪项服务使用哪个来源?
| 服务 | 推荐来源 | 备注 |
|---|---|---|
| **Home Assistant Core** | `/config/home-assistant.log`(文件) | 默认激活 —— 足够使用,无需 Docker 条目 |
| **Nginx Proxy Manager** | `Docker: Nginx Proxy Manager` | 外部访问的最重要来源 —— 真实 IP |
| **2FAuth** | NPM(首选)+ `Docker: 2FAuth` | Docker 日志仅显示 `172.30.32.1`;NPM 通过 HTTP 500 检测失败的登录 |
| **Vaultwarden** | `Docker: Vaultwarden` + NPM | Vaultwarden 直接记录日志,但外部访问通过 NPM 进行 |
| **DokuWiki** | `Docker: DokuWiki` + `auth.log` 文件 | DokuWiki 将失败的登录写入 `data/log/auth.log`(通过文件搜索查找) |
| **Nextcloud** | `Docker: Nextcloud` | Nextcloud 将失败的登录记录到 stdout |
| **Webtrees** | NPM | Webtrees 在登录失败时返回 HTTP 200;NPM 模式检测登录重定向 |
| **SSH** | 文件:`/config/home-assistant.log` | 默认规则中包含 SSH 模式 |
### 日志文件搜索
Addons 选项卡具有**文件搜索**功能,可在所有 addon 目录中查找日志文件:
- 输入例如 `auth.log` 以查找所有 auth.log 文件
- **预览**显示文件的最后几行
- 找到的路径可以作为手动来源添加
### 健康检查
Addons 选项卡中的 **Health Check** 按钮会检查所有已启用的日志源:
- **绿色(正常)** – 来源有近期的日志条目(过去 7 天内)
- **红色(过期)** – 来源没有近期的条目 → 该行将以红色高亮显示
- **灰色(空)** – 来源为空或无法读取
这让您可以快速识别已启用的来源是否确实在提供数据。
### 未使用的来源
由 Guardian 发现但不需要的日志文件可以通过 **Reassign → Unused** 标记为未使用。它们将在单独的组中显示为灰色并且不被监控。这可以防止无关的来源使概览变得杂乱。
## Rules 选项卡
### 预配置规则
| 规则 ID | 检测内容 |
|---|---|
| `ha_ban` | HA 自身的封禁条目 |
| `nginx_auth` | Nginx 401/403 身份验证错误 |
| `generic_fail` | 通用登录失败模式 |
| `ssh_fail` | SSH 登录失败 |
| `nextcloud` | Nextcloud 登录失败 |
| `vaultwarden` | Vaultwarden/Bitwarden 登录失败 |
| `dovecot_postfix` | Dovecot/Postfix 邮件登录失败 |
| `laravel_auth` | Laravel 应用程序 |
| `webtrees_fail` | Webtrees(登录重定向时的 HTTP 200) |
| `dokuwiki_auth` | DokuWiki auth.log |
| `2fauth_login` | 2FAuth 直接访问 |
| `ha_core_invalid_auth` | HA Core invalid_auth 事件 |
| `http_login_fail` | 通用的 HTTP 4xx/5xx 登录端点 |
| `npm_proxy` | Nginx Proxy Manager – 通过 `[Client X.X.X.X]` 获取真实客户端 IP |
### 管理规则
- **切换** – 启用/禁用规则而无需删除它
- **编辑** – 修改模式、描述和标志;带有实时测试器
- **复制** – 用作新规则的基础
- **删除** – 移除规则
- **🔧 恢复出厂设置** – 将所有规则重置为默认值
### 创建自定义规则
1. 点击 **+ New Rule**
2. 选择一个唯一的 ID(snake_case,例如 `my_app_fail`)
3. 带有 IP 捕获组的正则表达式模式:
Login failed.*from\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
4. 针对示例日志行进行**测试**
5. 保存 – 规则立即生效
### 不匹配的身份验证行
在规则下方,显示了包含身份验证关键字但没有规则匹配的日志行。这对于开发新规则很有用。
## Whitelist 选项卡
### 自动白名单
首次打开 Guardian UI 时,会自动检测您的公共 IP(通过 ipinfo.io)并将其添加到白名单中。如果您的 IP 发生变化,下次访问时将添加新 IP 并移除旧 IP。
- **禁用** → 点击“Disable”并确认
- **重新启用** → 点击“Enable Auto-whitelist”
### 默认加入白名单
- `127.0.0.1` – localhost
- `172.30.32.0/24` – HA 内部网络
- `192.168.0.0/16` – 本地家庭网络
### 手动条目
- 单个 IP:`91.42.192.232`
- CIDR 范围:`192.168.178.0/24`
## 仪表板
显示配置时间窗口内检测到的所有失败的登录尝试。
| 列 | 含义 |
|------|
| Time | 检测的时间戳 |
| IP Address | 攻击的 IP |
| Source | 日志来源 |
| Attempts | 该 IP 的失败尝试次数 |
| Status | `ATTEMPT` 或 `BANNED` |
| Log Line | 原始日志行 |
| Details | 模态框中的完整行 |
## 被封禁的 IP
所有被封禁 IP 的概览。
- **Details** – 显示哪些日志条目触发了封禁
- **Unban** – 立即解除封禁
- **Ban IP** – 手动封禁,可选择持续时间和原因
## 架构说明
### 为什么许多 addon 只显示 172.30.32.1 作为客户端 IP?
HA 通过内部代理路由外部流量。因此,addon 始终将 `172.30.32.1` 视为客户端 IP,而不是真实的外部 IP。Nginx Proxy Manager 位于此代理的**前端**并能看到真实 IP —— 这就是为什么 NPM 是最重要的日志来源。
### 跨来源计数
来自不同 addon 的失败登录会被**一起计算**:
这是有意为之:同时探测多个服务的攻击者应该被封禁得更快。
## 常见问题
**问:封禁出现在列表中,但 IP 实际上没有被阻止?**
→ HA 实时监控 `ip_bans.yaml` —— 无需重启。检查配置目录中的 `ip_bans.yaml`,确认该 IP 确实在其中。
**问:尽管发生了登录失败,但没有警报?**
→ 检查 Addons 选项卡以查看是否启用了相关来源。对于外部访问:启用 NPM 日志。
**问:如何查找某个 addon 的日志文件?**
→ Addons 选项卡 → **Log File Search** → 输入文件名(例如 `auth.log`)。
**问:CrowdSec 集成是如何工作的?**
→ Guardian 直接将封禁发送到 CrowdSec LAPI。有关设置,请参阅[CrowdSec 集成](#crowdsec-integration)。封禁和解封会自动同步。
**问:我可以将 Guardian 与 CrowdSec 同时运行吗?**
→ 可以!Guardian 注册为一台 CrowdSec 机器并直接将封禁发送到 LAPI。CrowdSec 自身的场景和 Guardian 的封禁相辅相成。
**问:如何为自定义应用程序创建规则?**
→ Rules 选项卡 → **+ New Rule** → 包含用于 IP 地址的捕获组 `(\d{1,3}(?:\.\d{1,3}){3})` 的正则表达式。
**问:如果 CrowdSec 无法访问会怎样?**
→ 封禁仍会写入 `ip_bans.yaml`(如果已启用)。CrowdSec 的错误会被记录下来,但不会阻止封禁过程。
## 许可证
MIT License
## 链接
- [GitHub 仓库](https://github.com/gregorwolf1973/ha-guardian)
- [问题与功能请求](https://github.com/gregorwolf1973/ha-guardian/issues)
标签:CrowdSec, Home Assistant, IP封禁, TLS, 智能家居, 物联网, 请求拦截, 逆向工具, 防御工具, 防暴力破解