漏洞管理平台架构:main.db + 每应用独立 SQLite 的多库设计

数据库拆分设计

/database
    main.db          ← 用户、管理员、应用列表
    java.db          ← Java 漏洞、CVE、POC、EXP
    mysql.db         ← MySQL 漏洞、CVE、POC、EXP
    redis.db
    nginx.db

每个应用独立 SQLite 的优点:

  • 某应用数据损坏不影响整个系统
  • 可单独备份或迁移到 PostgreSQL
  • 漏洞数据量大时不会拖慢其他应用的查询

main.db 表结构

-- 用户表
CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT UNIQUE,
    password TEXT,        -- bcrypt hash
    role TEXT,            -- superadmin / admin / user
    status INTEGER,       -- 0=禁用 1=正常
    created_at DATETIME
);

-- 应用注册表
CREATE TABLE applications (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT,            -- "java"
    db_name TEXT,         -- "java.db"
    db_path TEXT,         -- "/database/java.db"
    created_at DATETIME
);

应用数据库(每个应用独立)

CREATE TABLE vulnerabilities (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT,
    description TEXT,
    severity TEXT,        -- critical/high/medium/low
    affected_version TEXT,
    fixed_version TEXT,
    created_at DATETIME
);

CREATE TABLE cves (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    cve_id TEXT,          -- CVE-2024-12345
    cvss REAL,
    description TEXT
);

CREATE TABLE pocs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT,
    file_path TEXT,       -- /uploads/java/uuid.py
    description TEXT
);

CREATE TABLE exps (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT,
    file_path TEXT,
    description TEXT
);

-- 多对多关联
CREATE TABLE vulnerability_pocs (vuln_id INT, poc_id INT);
CREATE TABLE vulnerability_exps (vuln_id INT, exp_id INT);
CREATE TABLE vulnerability_cves (vuln_id INT, cve_id INT);

动态创建应用数据库

添加应用时,后端自动创建 SQLite 文件并初始化表:

// NestJS service
async createApplication(name: string) {
    const dbPath = path.join("database", `${name}.db`);
    const db = new Database(dbPath);

    // 初始化表结构
    db.exec(`
        CREATE TABLE IF NOT EXISTS vulnerabilities (...);
        CREATE TABLE IF NOT EXISTS cves (...);
        CREATE TABLE IF NOT EXISTS pocs (...);
        CREATE TABLE IF NOT EXISTS exps (...);
    `);
    db.close();

    // 记录到 main.db
    await this.mainDb.run(
        "INSERT INTO applications (name, db_name, db_path) VALUES (?, ?, ?)",
        [name, `${name}.db`, dbPath]
    );
}

RBAC 三角色权限

角色权限
superadmin全部权限,管理用户和管理员
admin管理漏洞/CVE/POC/EXP,不能添加管理员
user只能查询漏洞和下载 POC/EXP

JWT 鉴权:

// NestJS Guard
@Injectable()
export class RolesGuard implements CanActivate {
    canActivate(context: ExecutionContext): boolean {
        const { user } = context.switchToHttp().getRequest();
        const requiredRoles = this.reflector.get<string[]>("roles", context.getHandler());
        return requiredRoles.includes(user.role);
    }
}

文件安全

POC/EXP 文件禁止通过静态目录暴露:

❌  GET /uploads/java/poc.py      (直接静态访问)
✅  GET /api/download/poc/:id     (JWT 鉴权后返回文件流)
@Get("download/poc/:id")
@UseGuards(JwtAuthGuard)
async downloadPoc(@Param("id") id: string, @Res() res: Response) {
    const poc = await this.pocService.findById(id);
    res.download(poc.file_path, poc.name);
}

上传文件名用 UUID 避免路径遍历:

const filename = `${uuidv4()}${path.extname(file.originalname)}`;

版本匹配建议

不要简单字符串比对,用 semver 范围查询:

import semver from "semver";

function isVulnerable(version: string, affected: string): boolean {
    // affected: ">=8.0.0 <8.0.31"
    return semver.satisfies(version, affected);
}

"8.0.9" < "8.0.31" 用字符串比较会得到错误结果(字典序 9 > 3),必须用 semver 数字化比较。

推荐技术栈

推荐
后端框架NestJS 或 Next.js App Router
ORMPrisma(SQLite 支持好,类型安全)
鉴权JWT + bcrypt
前端Vue3 + Element Plus 或 shadcn/ui
部署PM2 + Nginx 反代