- 新增文档模板和导航结构 - 实现服务器基础API路由和控制器 - 添加扩展插件配置和前端框架 - 引入多租户和权限管理模块 - 集成日志和数据库配置 - 添加核心业务模型和类型定义
107 lines
3.5 KiB
TypeScript
107 lines
3.5 KiB
TypeScript
import crypto from 'crypto';
|
|
import db from '../../config/database';
|
|
import { logger } from '../../utils/logger';
|
|
|
|
export interface NodeIdentity {
|
|
nodeId: string;
|
|
hardwareFingerprint: string;
|
|
clientCertFingerprint?: string; // [CORE_SEC_07] mTLS 证书指纹
|
|
publicKey: string;
|
|
status: 'PENDING' | 'TRUSTED' | 'REVOKED';
|
|
lastSeenAt: Date;
|
|
}
|
|
|
|
/**
|
|
* [CORE_SEC_04] 零信任节点身份管理服务
|
|
* @description 结合硬件指纹与非对称加密,确保只有受信任的物理设备能接入 Hub
|
|
*/
|
|
export class NodeIdentityService {
|
|
private static readonly TABLE_NAME = 'cf_node_identities';
|
|
|
|
/**
|
|
* 注册/更新节点身份 (基于硬件指纹与 mTLS 证书)
|
|
*/
|
|
static async registerNode(params: {
|
|
nodeId: string;
|
|
hardwareFingerprint: string;
|
|
clientCertFingerprint?: string;
|
|
publicKey: string;
|
|
}): Promise<boolean> {
|
|
const { nodeId, hardwareFingerprint, clientCertFingerprint, publicKey } = params;
|
|
|
|
const existing = await db(this.TABLE_NAME).where({ node_id: nodeId }).first();
|
|
|
|
if (existing) {
|
|
// 零信任校验:如果硬件指纹或证书指纹不匹配,拒绝更新
|
|
if (existing.hardware_fingerprint !== hardwareFingerprint) {
|
|
logger.error(`[ZeroTrust] Node ID ${nodeId} hardware fingerprint mismatch!`);
|
|
return false;
|
|
}
|
|
|
|
if (clientCertFingerprint && existing.client_cert_fingerprint && existing.client_cert_fingerprint !== clientCertFingerprint) {
|
|
logger.error(`[ZeroTrust] Node ID ${nodeId} mTLS certificate mismatch! Potential spoofing.`);
|
|
return false;
|
|
}
|
|
|
|
await db(this.TABLE_NAME).where({ node_id: nodeId }).update({
|
|
public_key: publicKey,
|
|
client_cert_fingerprint: clientCertFingerprint || existing.client_cert_fingerprint,
|
|
last_seen_at: new Date(),
|
|
updated_at: new Date()
|
|
});
|
|
} else {
|
|
await db(this.TABLE_NAME).insert({
|
|
node_id: nodeId,
|
|
hardware_fingerprint: hardwareFingerprint,
|
|
client_cert_fingerprint: clientCertFingerprint,
|
|
public_key: publicKey,
|
|
status: 'PENDING',
|
|
last_seen_at: new Date(),
|
|
created_at: new Date(),
|
|
updated_at: new Date()
|
|
});
|
|
logger.info(`[ZeroTrust] New node registered: ${nodeId} (mTLS: ${!!clientCertFingerprint})`);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 验证节点签名的请求负载 (Challenge-Response)
|
|
*/
|
|
static async verifyNodeSignature(nodeId: string, payload: any, signature: string): Promise<boolean> {
|
|
const node = await db(this.TABLE_NAME).where({ node_id: nodeId, status: 'TRUSTED' }).first();
|
|
if (!node) return false;
|
|
|
|
try {
|
|
const verifier = crypto.createVerify('SHA256');
|
|
verifier.update(JSON.stringify(payload));
|
|
return verifier.verify(node.public_key, signature, 'base64');
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 初始化数据库表
|
|
*/
|
|
static async initTable() {
|
|
const exists = await db.schema.hasTable(this.TABLE_NAME);
|
|
if (!exists) {
|
|
logger.info(`📦 Creating ${this.TABLE_NAME} table...`);
|
|
await db.schema.createTable(this.TABLE_NAME, (table) => {
|
|
table.string('node_id', 64).primary();
|
|
table.string('hardware_fingerprint', 128).notNullable();
|
|
table.string('client_cert_fingerprint', 128);
|
|
table.text('public_key').notNullable();
|
|
table.string('status', 16).defaultTo('PENDING');
|
|
table.timestamp('last_seen_at');
|
|
table.timestamps(true, true);
|
|
|
|
table.index(['hardware_fingerprint']);
|
|
});
|
|
logger.info(`✅ Table ${this.TABLE_NAME} created`);
|
|
}
|
|
}
|
|
}
|