Steph-ux/bind9-web-ui

GitHub: Steph-ux/bind9-web-ui

一个通过 Web 仪表板简化 BIND9 配置与防火墙管理的安全控制面板,解决手动编辑配置易出错的问题。

Stars: 0 | Forks: 0

# BIND9 Web UI / 管理面板 **缺失的 BIND9 Web 界面。** 管理 DNS 区域、记录、ACL、TSIG 密钥、防火墙和远程服务器——全部通过现代化仪表板完成。 ⚡ 专为系统管理员、DevOps 和家庭实验室用户构建。 Copyright © 2025 Stephane ASSOGBA ![TypeScript](https://img.shields.io/badge/TypeScript-5.6-3178C6?logo=typescript&logoColor=white) ![Express](https://img.shields.io/badge/Express-5.0-000?logo=express) ![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=black) ![SQLite](https://img.shields.io/badge/SQLite-3-003B57?logo=sqlite) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-Supported-4169E1?logo=postgresql&logoColor=white) ![MySQL](https://img.shields.io/badge/MySQL-Supported-4479A1?logo=mysql&logoColor=white) ![License: MIT](https://img.shields.io/badge/License-MIT-green) ## 为什么? BIND9 是功能最强大的 DNS 服务器之一,但: - 没有官方 Web 界面 - 配置复杂 - 手动编辑容易出错 该项目通过提供一个现代化、安全且用户友好的控制面板来解决这些问题。 ## 截图
Dashboard Real-time Logs SSH Connections
Dashboard Real-time Logs SSH Connections
## 功能特性 ### DNS 管理 - **区域** — 创建、修改和删除 DNS 区域(主区域、从区域、转发区域) - **记录** — 对 A、AAAA、CNAME、MX、TXT、NS、SOA、PTR、SRV 记录提供完整的 CRUD 操作 - **区域文件** — 自动生成和解析 BIND9 区域文件 - **反向 DNS 自动创建** — 添加 A 记录时自动创建区域和 PTR 记录 - **现有配置导入** — 自动从 `named.conf`(包括包含的文件)导入区域、ACL 和密钥 ### 安全与网络 - **ACL** — 管理访问控制列表以保护查询和传输 - **区域传输** — 配置允许从属服务器(Secondary NS)进行传输的简化方法 - **TSIG 密钥** — 管理身份验证密钥(hmac-sha256 等),支持包含 `.key` 文件 - **防火墙** — 管理防火墙,支持自动检测后端(UFW、firewalld、nftables、iptables),开启/关闭端口、按 IP 设置规则、一键切换后端 - **DNS 防火墙(RPZ)** — 通过响应策略区域进行 DNS 阻断:支持导入阻断列表(如 HaGeZi 等)、CRUD 管理、服务器端分页过滤、与 BIND9 的双向同步、支持 1M+ 条目 - **RBAC** — 用户角色管理(管理员、操作员、查看者) - **域名隔离** — 限制查看者对特定区域的访问 - **API 令牌** — 带权限和作用域的 API 令牌,用于程序化访问 ### 复制 - **从属服务器** — 通过 SSH 添加从属服务器并自动同步区域文件 - **区域绑定** — 选择性同步区域到每个服务器 - **冲突检测** — 自动检测序列号不匹配和缺失区域 - **Notify** — 修改后向从属服务器发送 BIND9 Notify - **统计信息** — 同步统计和历史记录 ### 健康检查与通知 - **自动检查** — 定期检查 BIND9 服务器健康状态 - **通知通道** — 通过电子邮件、Webhook HTTP 或 Slack 发送告警 - **SSRF 保护** — 阻止通知通道中的私有/内部 URL(Webhook/Slack 和区域文件导入) ### DNSSEC - **密钥管理** — 生成 KSK/ZSK 密钥(ECDSAP256、ECDSAP384、RSASHA256、RSASHA512) - **区域签名** — 通过 rndc dnssec 自动签名区域 - **密钥轮换** — 移除并删除密钥并进行验证 - **条目验证** — 防止在 rndc 参数中注入命令 ### 备份 - **类型** — 自动、手动、快照 - **范围** — 完整、区域、配置、单个区域 - **恢复** — 恢复时更新现有记录 - **计划** — 自动计划备份 ### 配置 - **配置编辑器** — 编辑 `named.conf.options` 和 `named.conf.local` 并自动保存 - **快照** — 数据库中的配置历史记录 - **自动备份** — 每次修改前自动备份,验证错误时回滚 ### 监控 - **仪表板** — 实时概览(区域、记录、CPU、内存、最近日志) - **服务器状态** — 详细系统指标(CPU、内存、网络接口、打开文件) - **实时日志** — WebSocket 流式传输 BIND9 和系统日志,支持过滤 - **rndc 命令** — 直接执行 rndc 命令(重新加载、刷新、状态、统计、重新配置、查询日志) ### 远程 SSH 连接 - **多服务器** — 单个面板管理多个 BIND9 服务器 - **自动检测** — 自动检测远程服务器上的 BIND9 路径(Debian、CentOS、FreeBSD) - **自动检测防火墙** — 自动检测活动防火墙后端和远程服务器上的可用后端 - **连接测试** — SSH 连接测试,显示服务器信息(操作系统、BIND9 版本、状态) - **切换** — 在本地模式和 SSH 模式之间透明切换 - **重新连接** — 启动时自动恢复活动连接 ## 技术栈 | 层 | 技术 | |----|------| | **前端** | React 19, Vite 7, TypeScript, Tailwind CSS 4, shadcn/ui, Recharts, Lucide React, Wouter | | **后端** | Node.js, Express 5, TypeScript, WebSocket (ws) | | **数据库** | SQLite (better-sqlite3) / PostgreSQL (pg) / MySQL (mysql2), Drizzle ORM | | **SSH** | ssh2(连接、执行命令、SFTP) | | **验证** | Zod, drizzle-zod | ## 项目架构 ``` Bind-Config/ ├── client/ # Frontend React │ └── src/ │ ├── components/ │ │ ├── layout/ │ │ │ └── DashboardLayout.tsx # Layout principal + sidebar │ │ └── ui/ # Composants shadcn/ui │ ├── pages/ │ │ ├── dashboard.tsx # Vue d'ensemble │ │ ├── zones.tsx # Gestion des zones DNS │ │ ├── config.tsx # Éditeur de configuration │ │ ├── acls.tsx # ACLs & TSIG Keys │ │ ├── logs.tsx # Logs temps réel (WebSocket) │ │ ├── status.tsx # Métriques serveur │ │ ├── connections.tsx # Connexions SSH distantes │ │ ├── firewall.tsx # Gestion du pare-feu │ │ ├── firewall-dns.tsx # DNS Firewall (RPZ) │ │ ├── replication-page.tsx # Réplication & sync │ │ ├── zone-editor.tsx # Éditeur de zone (records + DNSSEC) │ │ ├── users-page.tsx # Gestion des utilisateurs │ │ ├── api-tokens.tsx # Jetons d'API │ │ ├── blacklist.tsx # Liste noire d'IPs │ │ └── profile.tsx # Profil utilisateur │ ├── lib/ │ │ └── api.ts # Client API typé │ └── App.tsx # Router │ ├── server/ # Backend Express │ ├── index.ts # Point d'entrée serveur │ ├── routes.ts # Tous les endpoints REST + WebSocket │ ├── auth.ts # Authentification, sessions, RBAC middleware │ ├── bind9-service.ts # Service BIND9 (local + SSH) │ ├── replication-service.ts # Service de réplication (sync, conflits, slave config) │ ├── health-service.ts # Service de health checks + notifications │ ├── dnssec-service.ts # Service DNSSEC (génération clés, signature, rotation) │ ├── backup-service.ts # Service de sauvegarde/restauration │ ├── firewall-service.ts # Service Pare-feu (UFW/firewalld/nftables/iptables) │ ├── ssh-manager.ts # Gestionnaire de connexions SSH │ ├── storage.ts # Couche d'accès aux données (Drizzle) │ ├── db.ts # Initialisation SQLite │ └── vite.ts # Middleware Vite pour le dev │ ├── shared/ │ ├── schema.ts # Schéma Drizzle SQLite (20 tables) │ ├── schema-pg.ts # Schéma Drizzle PostgreSQL │ └── schema-mysql.ts # Schéma Drizzle MySQL │ ├── data/ │ └── bind9admin.db # Base SQLite (auto-créée) │ ├── drizzle.config.ts # Configuration Drizzle Kit ├── package.json ├── tsconfig.json └── vite.config.ts ``` ## ⚡ 快速开始 ``` # 1 — Cloner git clone https://github.com/Steph-ux/bind9-web-ui.git cd bind9-web-ui # 2 — Installer (Linux : sudo apt install -y build-essential python3) npm install # 3 — 数据库 npm run db:push # 4 — 启动 npm run dev # 5 — 打开 http://localhost:3001 → admin / admin ``` ## 详细安装 ### 先决条件 - **Node.js** 18+ - **npm** 或 **yarn** - (可选)本地或通过 SSH 可访问的 BIND9 服务器 ### 1. 克隆项目 ``` git clone https://github.com/Steph-ux/bind9-web-ui.git cd bind9-web-ui ``` ### 2. Linux 先决条件(编译原生 SQLite 模块) ``` sudo apt update && sudo apt install -y build-essential python3 ``` ### 3. 安装依赖 ``` npm install ``` ### 4. 初始化数据库 ``` npm run db:push ``` 这会自动创建 `data/bind9admin.db` 文件并包含所有数据表。 ### 5. 启动开发环境 ``` npm run dev ``` 服务器将在 **http://localhost:3001** 启动(后端和前端一起服务)。 ### 6. 生产构建 ``` npm run build npm start ``` ### 7. 首次登录 首次启动时,会自动创建一个管理员用户: - **URL**:http://localhost:3001 - **用户名**:`admin` - **密码**:`admin` ## 配置 ### 环境变量 | 变量 | 默认值 | 描述 | |------|--------|------| | `PORT` | `3001` | 服务器端口 | | `DB_TYPE` | `sqlite` | 数据库类型:`sqlite`、`postgresql`、`mysql` | | `DATABASE_URL` | `data/bind9admin.db` | SQLite 路径或 PG/MySQL 连接 URL | | `SESSION_SECRET` | *(开发环境随机)* | 会话密钥(生产环境必需) | | `BIND9_CONF_DIR` | `/etc/bind` | 本地模式下 BIND9 配置目录 | | `BIND9_ZONE_DIR` | `/var/cache/bind` | 本地模式下区域文件目录 | `RNDC_BIN` | `rndc` | rndc 二进制文件路径 | | `NAMED_CHECKCONF` | `named-checkconf` | named-checkconf 路径 | ### 工作模式 应用程序支持两种模式: #### 本地模式(默认) 面板直接通过 `rndc` 命令和直接访问配置文件与本地 BIND9 交互。 #### SSH 模式(远程) 面板通过 SSH 连接到远程 BIND9 服务器。所有命令和文件操作都通过 SSH 连接传输。 要配置 SSH 连接: 1. 侧边栏进入 **Connections** 2. 点击 **Add Connection** 3. 填写主机、SSH 端口、用户名和密码 4. (可选)BIND9 路径会自动检测,也可手动指定 5. 点击 **Test** 测试连接并检测路径 6. 点击 **Activate** 切换到 SSH 模式 ## REST API ### 仪表板 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/dashboard` | 仪表板聚合数据 | ### 区域 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/zones` | 列出所有区域 | | GET | `/api/zones/:id` | 获取区域及其记录详情 | | POST | `/api/zones` | 创建区域 | | PUT | `/api/zones/:id` | 修改区域 | | DELETE | `/api/zones/:id` | 删除区域 | ### DNS 记录 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/zones/:id/records` | 列出区域记录 | | POST | `/api/zones/:id/records` | 添加记录 | | PUT | `/api/records/:id` | 修改记录 | | DELETE | `/api/records/:id` | 删除记录 | ### 配置 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/config/:section` | 读取配置部分 | | PUT | `/api/config/:section` | 保存配置部分 | ### ACL | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/acls` | 列出 ACL | | POST | `/api/acls` | 创建 ACL | | PUT | `/api/acls/:id` | 修改 ACL | | DELETE | `/api/acls/:id` | 删除 ACL | ### TSIG 密钥 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/keys` | 列出密钥(隐藏密钥值) | | POST | `/api/keys` | 创建密钥 | | DELETE | `/api/keys/:id` | 删除密钥 | ### 日志 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/logs?level=&source=&search=` | 带过滤器的日志列表 | | DELETE | `/api/logs` | 清空日志 | | WS | `/ws/logs` | 实时日志流 | ### 服务器状态 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/status` | BIND9 状态和系统指标 | ### rndc 命令 | 方法 | 端点 | 描述 | |------|------|------| | POST | `/api/rndc/:command` | 执行 rndc 命令 | 允许的命令:`reload`、`flush`、`status`、`stats`、`reconfig`、`dumpdb`、`querylog` ### SSH 连接 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/connections` | 列出连接 | | POST | `/api/connections` | 创建连接 | | PUT | `/api/connections/:id` | 修改连接 | | DELETE | `/api/connections/:id` | 删除连接 | | POST | `/api/connections/:id/test` | 测试 SSH 连接 | | POST | `/api/connections/test` | 使用内联凭据测试 | | PUT | `/api/connections/:id/activate` | 切换到 SSH 模式 | | PUT | `/api/connections/deactivate` | 切换回本地模式 | ### 防火墙 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/firewall/status` | 防火墙状态(活动/非活动、后端、规则) | | GET | `/api/firewall/rules` | 列出规则 | | POST | `/api/firewall/rules` | 添加规则(允许/拒绝) | | DELETE | `/api/firewall/rules/:id` | 删除规则 | | POST | `/api/firewall/toggle` | 启用/禁用防火墙 | | POST | `/api/firewall/backend` | 切换防火墙后端(ufw/firewalld/nftables/iptables) | ### DNS 防火墙(RPZ) | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/rpz?page=&limit=&search=&type=` | 分页获取 RPZ 条目 | | GET | `/api/rpz/stats` | 统计信息(总计、按类型) | | POST | `/api/rpz` | 添加 RPZ 条目 | | DELETE | `/api/rpz/:id` | 删除 RPZ 条目 | | DELETE | `/api/rpz` | 删除所有条目(管理员) | | GET | `/api/rpz/zone-file` | 读取 BIND9 RPZ 区域文件 | | POST | `/api/rpz/sync` | 从 BIND9 区域文件同步 | | POST | `/api/rpz/import` | 从文本(区域文件或域名列表)导入 | | POST | `/api/rpz/import-url` | 从 URL 导入(最大 200MB,1M 条目,超时 120 秒) | ### 复制 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/replication` | 列出复制服务器(隐藏凭据) | | GET | `/api/replication/stats` | 复制统计信息 | | POST | `/api/replication` | 添加复制服务器 | | PUT | `/api/replication/:id` | 修改服务器 | | DELETE | `/api/replication/:id` | 删除服务器 | | POST | `/api/replication/:id/test` | 测试 SSH 连接 | | POST | `/api/replication/:id/sync` | 同步所有区域到服务器 | | POST | `/api/replication/sync-all` | 同步到所有活动服务器 | | POST | `/api/replication/notify/:domain` | 通知域到从属服务器 | | GET | `/api/replication/conflicts` | 列出冲突 | | POST | `/api/replication/conflicts/detect` | 检测冲突 | | PUT | `/api/replication/conflicts/:id/resolve` | 解决冲突 | | PUT | `/api/replication/conflicts/resolve-all` | 解决所有冲突 | | GET | `/api/replication/:serverId/bindings` | 区域-服务器绑定 | | PUT | `/api/replication/:serverId/bindings` | 更新绑定 | | GET | `/api/sync-history` | 同步历史记录 | | GET | `/api/sync-metrics` | 同步指标 | ### 健康检查与通知 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/health-checks` | 列出健康检查结果 | | POST | `/api/health-checks/run` | 运行健康检查 | | GET | `/api/notification-channels` | 列出通知通道(配置隐藏) | | POST | `/api/notification-channels` | 创建通道(电子邮件/Webhook/Slack) | | PUT | `/api/notification-channels/:id` | 修改通道 | | DELETE | `/api/notification-channels/:id` | 删除通道 | ### DNSSEC | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/dnssec/keys` | 列出SEC 密钥 | | POST | `/api/dnssec/generate-key` | 生成密钥(KSK/ZSK) | | POST | `/api/dnssec/sign-zone/:zoneId` | 签名区域 | | GET | `/api/dnssec/status/:zoneId` | 获取区域签名状态 | | POST | `/api/dnssec/retire-key/:keyId` | 移除密钥 | | DELETE | `/api/dnssec/keys/:keyId` | 删除密钥(管理员) | ### 备份 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/backups` | 列出备份 | | POST | `/api/backups` | 创建备份(自动/手动/快照) | | POST | `/api/backups/:id/restore` | 恢复备份(管理员) | | DELETE | `/api/backups/:id` | 删除备份(管理员) | ### API 令牌 | 方法 | 端点 | 描述 | |------|------|------| | GET | `/api/tokens` | 列出令牌 | | POST | `/api/tokens` | 创建令牌 | | DELETE | `/api/tokens/:id` | 撤销令牌 | ## 导入现有配置 应用程序设计为可适应现有的 BIND9 安装,而不会覆盖任何内容。 ### 启动时 1. **递归检测**:应用程序分析 `named.conf` 并跟随所有包含的文件。 2. **区域**:`named.conf.local` 中定义的区域会被导入到数据库。 3. **ACL**:`named.conf.acls` 中定义的 ACL 会被导入。 4. **TSIG 密钥**:`named.conf.keys` 中定义的密钥 **以及** 任何其他包含的文件(例如 `/etc/bind/transfer.key`)会被导入。 ### 冲突处理 - 现有数据会被保留。 - 如果密钥(例如 `transfer-key`)被导入,它会在仪表板中显示。 - 应用程序随后会将此密钥写入 `named.conf.keys`。 - **建议**:一旦密钥在仪表板中可见,请从 `named.conf` 中删除旧的 `include "transfer.key";`,以避免 BIND9 重启时出现重复警告。 ## 数据库 应用程序通过 Drizzle ORM 支持 **3 种数据库引擎**: ### SQLite(默认) 无需额外配置。数据库会自动创建在 `data/bind9admin.db`。 ``` npm run db:push # Créer/mettre à jour les tables npx drizzle-kit studio # Visualiser la DB ``` ### PostgreSQL 1. 安装并配置 PostgreSQL 2. 创建数据库: ```sql CREATE USER bind9admin WITH PASSWORD 'bind9admin'; CREATE DATABASE bind9admin OWNER bind9admin; ``` 3. 配置环境变量: ```bash export DB_TYPE=postgresql export DATABASE_URL=postgresql://bind9admin:bind9admin@localhost:5432/bind9admin ``` 4. 推送架构: ```bash npm run db:push:pg ``` 5. 启动应用程序: ```bash npm run dev ``` ### MySQL 1. 安装并配置 MySQL 2. 创建数据库: ```sql CREATE USER 'bind9admin'@'localhost' IDENTIFIED BY 'bind9admin'; CREATE DATABASE bind9admin CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON bind9admin.* TO 'bind9admin'@'localhost'; FLUSH PRIVILEGES; ``` 3. 配置环境变量: ```bash export DB_TYPE=mysql export DATABASE_URL=mysql://bind9admin:bind9admin@localhost:3306/bind9admin ``` 4. 推送架构: ```bash npm run db:push:mysql ``` 5. 启动应用程序: ```bash npm run dev ``` ### 架构(20 张表,对所有引擎相同) ``` users → Comptes utilisateurs zones → Zones DNS (domain, type, serial, filePath) dns_records → Enregistrements DNS (A, AAAA, CNAME, MX, TXT, NS, etc.) acls → Listes de contrôle d'accès tsig_keys → Clés TSIG pour l'authentification DNS config_snapshots → Historique des configurations log_entries → Logs applicatifs connections → Connexions SSH distantes rpz_entries → Entrées DNS Firewall (RPZ) ip_blacklist → Liste noire d'IPs api_tokens → Jetons d'API pour accès programmatique user_domains → Assignations domaine→utilisateur (domain jailing) replication_servers → Serveurs de réplication secondaires replication_conflicts → Conflits de réplication détectés replication_zone_bindings → Bindings zone→serveur de réplication health_checks → Résultats de health checks notification_channels → Canaux de notification (email, webhook, Slack) sync_history → Historique des synchronisations dnssec_keys → Clés DNSSEC (KSK/ZSK) backups → Sauvegardes (auto, manual, snapshot) ``` ### Drizzle 命令 | 命令 | 描述 | |------|------| | `npm run db:push` | 同步 SQLite 架构 | | `npm run db:push:pg` | 同步 PostgreSQL 架构 | | `npm run db:push:mysql` | 同步 MySQL 架构 | | `npm run db:generate:pg` | 生成 PostgreSQL 迁移 | | `npm run db:generate:mysql` | 生成 MySQL 迁移 | | `npm run db:studio:pg` | PostgreSQL 的 Drizzle Studio | | `npm run db:studio:mysql` | MySQL 的 Drizzle Studio | ## 开发 ### 可用脚本 | 脚本 | 描述 | |------|------| | `npm run dev` | 启动开发服务器(后端 + 前端) | | `npm run dev:client` | 仅启动前端 Vite | | `npm run build` | 构建生产版本 | | `npm start` | 启动生产版本 | | `npm run check` | TypeScript 检查 | | `npm run db:push` | 同步数据库架构 | ### 添加新页面 1. 在 `client/src/pages/ma-page.tsx` 中创建组件 2. 在 `client/src/App.tsx` 中添加路由 3. 在侧边栏(`DashboardLayout.tsx`)中添加链接 4. (可选)在 `client/src/lib/api.ts` 中添加 API 函数 ### 添加新表 1. 在 `shared/schema.ts` 中定义架构 2. 在 `server/storage.ts` 中添加 CRUD 方法 3. 在 `server/routes.ts` 中添加路由 4. 推送架构:`npm run db:push` ## 安全 应用程序集成了多层安全机制: ### 认证与会话 - **密码哈希** — 使用 Node.js crypto 的 scrypt 和随机盐值 - **安全会话** — `express-session`,使用 `httpOnly`、`secure`(生产环境)、`sameSite` 的 Cookie - **会话密钥** — `SESSION_SECRET` 环境变量(生产环境必需,开发环境随机) - **强制密码更改** — 默认的 `admin` 用户在首次登录时必须更改密码 - **最小密码长度** — 所有密码(创建、更改、重置)至少 8 个字符 - **速率限制** — 每 IP 60 秒内最多 5 次登录尝试 - **专用路由** — `PUT /api/auth/password` 允许已认证用户更改自己的密码 ### 访问控制(RBAC) - **3 个角色**:`admin`(所有操作)、`operator`(DNS + 防火墙)、`viewer`(只读) - **中间件**:所有 API 路由使用 `requireAuth`、`requireAdmin`、`requireOperator` - **WebSocket 认证** — 连接前验证会话 Cookie ### 输入验证 - **Zod 架构** — 验证路由中的输入数据 - **字段白名单** — PUT 请求仅接受允许的字段(防止批量赋值) - **标识符验证** — 区域名称、ACL、TSIG 密钥、配置节通过正则表达式验证 - **BIND9 标识符清理** — 清理配置文件中注入的标识符(`sanitizeIdentifier`) - **命令验证** — 通过正则表达式验证执行的 rndc 命令 - **防火墙验证** — 端口(仅数字)、IP(CIDR 正则)、协议/操作/后端(白名单) - **通知通道验证** — 类型(电子邮件/Webhook/Slack)、根据类型验证配置、Webhook/Slack 的 SSRF 保护 - **备份验证** — 类型(自动/手动/快照)、范围(完整/区域/配置/单个区域)、需要 zoneId - **DNSSEC 验证** — keyType(KSK/ZSK)、算法(白名单)、keySize(数字) ### 防止注入 - **命令注入** — 在 shell 命令中插入前严格验证输入 - **SQL 注入** — 使用参数化 Drizzle ORM 查询 + LIKE 通配符转义 - **路径遍历** — 验证区域名称、SSH 路径和配置参数 - **配置注入** — 清理 BIND9 配置文件中的危险字符(`"';{}\n\r`) - **正则注入** — 在构建动态正则表达式前清理域名 - **SSRF** — 阻止通知通道和区域文件导入中的私有/内部 URL(RFC1918、CGN、链路本地、唯一本地) - **DNSSEC 注入** — 在 rndc dns 命令中插入前严格验证条目(域名、算法、keyType、keySize) - **备份验证** — 验证时间戳格式、文件存在性检查、恢复时更新现有记录 - **数据库索引** — 在频繁查询的列(sync_history、dnssec_keys、backups、health_checks)上建立索引以优化性能 ### 安全头 - `X-Content-Type-Options: nosniff` - `X-Frame-Options: DENY` - `X-XSS-Protection: 1; mode=block` - `Referrer-Policy: strict-origin-when-cross-origin` - `Permissions-Policy: camera=(), microphone=(), geolocation=()` - `Strict-Transport-Security`(生产环境) - `Content-Security-Policy`(生产环境) ### 错误处理 - 生产环境中的 500 错误不会泄露内部细节 - 密码和 SSH 私钥在 API 响应中被隐藏 ### 生产环境建议 ## DNS 防火墙(RPZ)— 强化 RPZ 模块已增强以支持大型阻断列表(最多 1M 条目,例如 HaGeZi TIF): | 保护 | 描述 | |------|------| | **Mutex BIND9** | `syncRpzZone()` 序列化区域写入 — 防止竞态条件 | | **异步解析** | `parseRpzBlocklist()` 每 50K 行 yield — 不阻塞事件循环 | | **批量 5000** | `getRpzExistingNames()` 将 1940 次往返减少到 194 次(针对 970K 个名称) | | **防抖 300ms** | 前端搜索不再每次按键都触发 API | | **索引名称** | `idx_rpz_entries_name` 加速前缀 LIKE 和去重 | | **分块 4MB** | 文件上传分块 — 避免 200MB 时内存崩溃 | | **LIKE 转义** | SQL 通配符(`%`、`_`、`\`)被转义 — 防止注入 | | **完整 SSRF** | 阻止私有范围:RFC1918、CGN、链路本地、唯一本地 | | **404 删除** | `DELETE /api/rpz/:id` 在条目不存在时返回 404 | | **强制小写** | 域名强制转换为小写 — 防止大小写重复 | ### SSH 远程连接的 sudoers 配置 为了让远程服务器上的 BIND9 命令和防火墙命令无需密码即可使用 sudo,请在 `/etc/sudoers.d/bind9` 中添加以下条目: ``` echo " ALL=(ALL) NOPASSWD: /usr/sbin/rndc, /usr/sbin/named, /usr/sbin/named-checkconf, /usr/sbin/ufw, /usr/sbin/nft, /usr/sbin/iptables, /usr/sbin/iptables-save, /usr/bin/firewall-cmd, /usr/bin/systemctl" > /etc/sudoers.d/bind9 chmod 440 /etc/sudoers.d/bind9 ```
标签:ACL, BIND9, DevOps工具, DNS控制面板, DNS管理, DNS记录, Express, firewalld, Homelab, iptables, MITM代理, nftables, PostgreSQL, React, SQLite, SSH, Sysadmin工具, Syscalls, TCP SYN 扫描, TSIG, TypeScript, UFW, Web UI, 区域管理, 反向DNS, 域名管理, 安全插件, 安全配置, 开源, 控制中心, 服务器管理, 测试用例, 现代仪表板, 自动化攻击, 自动检测, 自托管, 远程服务器, 防火墙规则