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







## 为什么?
BIND9 是功能最强大的 DNS 服务器之一,但:
- 没有官方 Web 界面
- 配置复杂
- 手动编辑容易出错
该项目通过提供一个现代化、安全且用户友好的控制面板来解决这些问题。
## 截图
## 功能特性
### 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
```
| Dashboard | Real-time Logs | SSH Connections |
![]() |
![]() |
![]() |
标签: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, 域名管理, 安全插件, 安全配置, 开源, 控制中心, 服务器管理, 测试用例, 现代仪表板, 自动化攻击, 自动检测, 自托管, 远程服务器, 防火墙规则


