ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于TypeScript的网络安全检测系统服务端架构与规则引擎实现

基于TypeScript的网络安全检测系统服务端架构与规则引擎实现 简介这是一套面向信息安全课程设计/毕业设计的基于TypeScript实现的网络安全检测系统服务端源码适合计算机、软件工程、网络安全等专业学生参考学习。源码按服务端工程化方式组织涵盖数据访问(dao)、业务服务(service)、路由过滤器(filter/router)、工具类(util)以及多环境配置(config)等模块能够帮助读者理解TypeScript在安全检测后端中的实际落地也可作为课程设计、项目初期演示或毕业设计的二次开发基础。压缩包共63个文件主要由29个TypeScript源文件、14个JSON配置文件、6个JS脚本以及少量CSS/SVG/HTML等界面资源组成整体仅241KB。TS源码承担核心服务逻辑JSON管理依赖与安全策略CSS/SVG/HTML则用于登录、注册及内容展示页面。项目已通过测试可正常运行目前已有587人学习下载配套的README与工程配置齐全适合快速上手并扩展成完整的网络安全检测平台。1. 基于 TypeScript 的网络安全检测系统服务端课程设计怎么做才不像玩具把“网络安全检测系统”做成课程设计最常见的翻车路径是用 Python 写一堆正则匹配跑通几个样例就交差。可一旦数据量上来、并发请求一多脚本型服务端立刻暴露出两个问题——事件处理没有类型约束字段名拼错一个就静默失败检测逻辑全是过程式 if-else想加一条规则得动主干代码。而用 TypeScript 写服务端正好卡在“演示效果好看”和“工程结构能讲清楚”的中间点上。这套基于 TypeScript 实现的网络安全检测系统服务端核心不是“检测算法多高深”而是把网络事件当成有结构的数据流来处理采集层收数据归一化成统一的事件对象检测层用可插拔的规则引擎跑判定最后告警层负责去重、落库、推送。对课程设计来说它最大的价值是把信息安全里“检测”这个环节用工程化的方式讲明白同时天然对接 Web 前端做可视化大屏。适合两类人一是信息安全专业要做课设、参赛的学生二是想从“会写 CRUD”跨到“懂安全业务逻辑”的 TypeScript 开发者。2. 服务端架构与数据流为什么 TS 比 Python 更适合做检测服务的骨架2.1 系统整体模块划分采集、归一化、检测、告警四层一个能演示、能答辩的网络安全检测服务端至少要包含三个模块数据接入层、检测引擎层、告警与存储层。数据接入层解决“事件从哪来”的问题常见做法是监听一个 HTTP 上报接口让模拟攻击脚本或者 Agent 把日志推上来检测引擎层是核心它消费事件流跑各种检测器告警与存储层把命中的结果写进数据库、推给前端。我一般会把数据接入层再拆成“上报接口”和“归一化适配器”两部分。上报接口只负责接收原始 JSON不参与任何判断归一化适配器把不同来源的日志Nginx 访问日志、端口连接记录、登录失败记录转成同一种内部事件结构。这一步非常关键——如果没有统一的事件模型每加一个数据源就要改一次检测逻辑代码很快就会变成一锅粥。下面是事件模型的 TypeScript 定义这是整个系统的地基// src/types/event.ts export type Protocol tcp | udp | http | dns | unknown; export interface SecurityEvent { id: string; // 事件唯一 ID用 crypto.randomUUID() 生成 timestamp: number; // 统一用 epoch 毫秒避免时区问题 srcIp: string; // 源 IP dstIp: string; // 目标 IP srcPort?: number; // 源端口连接类事件才有 dstPort?: number; // 目标端口 protocol: Protocol; // 协议类型 action: allow | deny | fail | success; // 动作结果 detail: Recordstring, unknown; // 原始字段兜底不丢信息 }这个接口的核心设计点是timestamp强制用 number 而不是 string。很多初学者会把时间存成 “2025-06-01 12:00:00” 这种格式后续做滑动窗口计算时全要转一遍。detail字段是兜底用的归一化过程中遇到无法映射的字段就先塞进去保证不丢原始信息调试时能追因。2.2 检测引擎的可插拔设计面向接口而不是面向实现检测引擎层最忌讳把所有判断堆在一个大函数里。正确姿势是定义一个统一的检测器接口每种攻击类型实现一个类通过注册机制挂到引擎上。这样新增检测能力时只需要“新增一个文件、注册一行代码”完全不动已有逻辑。// src/detectors/detector.ts import type { SecurityEvent } from ../types/event; export interface Alert { id: string; type: string; // 告警类型PORT_SCAN / BRUTE_FORCE / MALICIOUS_REQUEST severity: low | medium | high | critical; srcIp: string; dstIp?: string; message: string; timestamp: number; meta: Recordstring, unknown; } export interface Detector { // 每个检测器拿到一批事件返回命中的告警列表 detect(events: SecurityEvent[]): Alert[]; // 重置内部状态用于测试和规则热加载 reset(): void; }接口设计上有一个细节值得注意detect接收的是事件数组而不是单个事件。原因很简单像端口扫描、暴力破解这类行为单看一条记录什么都看不出来必须在一批事件里找统计特征。这个设计直接决定了后续所有检测器的写法。配合这个接口引擎层用一个注册表管理所有检测器并对外开放注册方法// src/engine.ts import type { Detector, Alert } from ./detectors/detector; import type { SecurityEvent } from ./types/event; export class DetectionEngine { private detectors: Mapstring, Detector new Map(); private alerts: Alert[] []; register(name: string, detector: Detector): void { this.detectors.set(name, detector); } unregister(name: string): void { this.detectors.delete(name); } async process(event: SecurityEvent): PromiseAlert[] { // 不阻塞事件消费先收集再统一跑检测 this.pendingEvents.push(event); // 每满 100 条或积压超过 500ms 就触发一轮检测 if (this.pendingEvents.length 100) { return this.flush(); } return []; } private flush(): Alert[] { const batch this.pendingEvents.splice(0); const hits: Alert[] []; for (const detector of this.detectors.values()) { const result detector.detect(batch); hits.push(...result); } return hits; } }这个引擎实现了批处理逻辑事件不一条一条喂给检测器而是攒到 100 条或者定时器触发时再批量跑。这么做有两个好处——第一减少了检测器的调用次数避免每个事件都遍历一遍全部规则第二滑动窗口类算法需要时间窗口内有足够多的样本批处理天然保证这一点。引擎内部维护pendingEvents队列process方法推入队列后判断是否触发flush。这里有一个内存控制的点如果长期凑不满 100 条比如演示环境流量很小必须有兜底定时器强制 flush否则事件会越积越多。我一般会用setInterval每 500ms 主动检查一次队列。2.3 TypeScript 选型理由类型安全如何直接降低安全系统的事故率选 TypeScript 而不是 Python不是性能问题而是工程问题。安全检测系统最怕的是“静默错误”数据读进来了字段对不上程序不报错只是检测结果一直不准。Python 字典取不到 key 返回 None后续计算全变 NaN排查几个小时。TypeScript 的编译期类型检查直接把这类问题挡在开发阶段。另一个实际优势是前端复用。课程设计几乎都要配可视化界面前后端共用 TypeScript 后事件类型、告警类型的定义可以抽成共享的类型文件前端拿到告警数据时字段提示、类型安全全都有保障。这会让答辩时的“系统设计”部分变得非常扎实——面试官问“为什么选 TypeScript”时可以从类型安全、前后端类型共享、生态成熟度三个角度回答比一句“我会这个”有说服力得多。3. 三个核心检测器的实现从滑动窗口到规则引擎代码可直接抄3.1 端口扫描检测滑动窗口统计 冷却时间机制端口扫描检测的逻辑一句话讲就是同一个源 IP 在短时间内访问了大量不常见端口。实现上用 Map 存储每个源 IP 的时间戳数组每次来新事件就把窗口外的旧时间戳剔除再看窗口内的数量是否超过阈值。// src/detectors/port-scan.detector.ts import type { Detector, Alert } from ./detector; import type { SecurityEvent } from ../types/event; export interface PortScanConfig { windowMs: number; // 时间窗口毫秒 threshold: number; // 窗口内访问不同端口的数量阈值 cooldownMs: number; // 同源 IP 告警冷却时间 } export class PortScanDetector implements Detector { private history: Mapstring, number[] new Map(); private lastAlertAt: Mapstring, number new Map(); private readonly config: PortScanConfig; constructor(config: PartialPortScanConfig {}) { this.config { windowMs: 10_000, threshold: 20, cooldownMs: 60_000, ...config, }; } detect(events: SecurityEvent[]): Alert[] { const alerts: Alert[] []; const now Date.now(); for (const ev of events) { if (ev.protocol ! tcp || ev.dstPort undefined) continue; const key ev.srcIp; const timestamps this.history.get(key) ?? []; // 只保留窗口内的事件 timestamps.push(ev.timestamp); this.history.set(key, timestamps.filter(t now - t this.config.windowMs)); // 统计不同目标端口数量排除 80/443 等常见端口 const distinctPorts new Set( this.history.get(key)!.map((_, i) i), // 简化示意实际应结合端口去重 ); void distinctPorts; const portCount this.countDistinctPorts(events, ev.srcIp); const lastTime this.lastAlertAt.get(key) ?? 0; if (portCount this.config.threshold now - lastTime this.config.cooldownMs) { alerts.push({ id: crypto.randomUUID(), type: PORT_SCAN, severity: medium, srcIp: ev.srcIp, message: 检测到疑似端口扫描行为${ev.srcIp} 在 ${this.config.windowMs / 1000}s 内访问了 ${portCount} 个不同端口, timestamp: now, meta: { windowMs: this.config.windowMs, portCount }, }); this.lastAlertAt.set(key, now); } } return alerts; } private countDistinctPorts(events: SecurityEvent[], srcIp: string): number { const ports new Setnumber(); for (const ev of events) { if (ev.srcIp srcIp ev.dstPort ! undefined) { ports.add(ev.dstPort); } } return ports.size; } reset(): void { this.history.clear(); this.lastAlertAt.clear(); } }三个核心参数值得细说。windowMs设 10 秒是取常见端口扫描工具的平均扫描速率threshold设 20意味着 10 秒内访问 20 个不同端口才算可疑。这个值在演示环境里建议调低到 10否则模拟攻击脚本要跑很久才能触发告警。cooldownMs必须设置否则扫描行为持续时同源 IP 会每秒刷一条告警把告警列表直接打爆。3.2 暴力破解检测失败次数统计 源 IP 维度聚合暴力破解的核心特征是“大量失败没有成功”。检测器维护每个源 IP 在时间窗口内的失败次数超过阈值就判定为攻击。这里要额外处理一个边界如果窗口内出现一次成功登录可以认为暴力破解已得逞此时应当发出 critical 级别的告警而不是继续数次数。// src/detectors/brute-force.detector.ts import type { Detector, Alert } from ./detector; import type { SecurityEvent } from ../types/event; export interface BruteForceConfig { windowMs: number; // 统计窗口 failThreshold: number; // 失败次数阈值 successAlert: boolean; // 是否对窗口内出现成功的事件单独告警 } export class BruteForceDetector implements Detector { private failCount: Mapstring, Array{ time: number; detail: string } new Map(); private readonly config: BruteForceConfig; constructor(config: PartialBruteForceConfig {}) { this.config { windowMs: 60_000, failThreshold: 10, successAlert: true, ...config, }; } detect(events: SecurityEvent[]): Alert[] { const alerts: Alert[] []; const now Date.now(); for (const ev of events) { // 只处理认证相关事件登录失败/成功 if (!ev.detail?.authType) continue; const key ${ev.srcIp}:${ev.dstIp}; if (ev.action fail) { const list this.failCount.get(key) ?? []; list.push({ time: ev.timestamp, detail: String(ev.detail.username ?? ) }); this.failCount.set(key, list.filter(x now - x.time this.config.windowMs)); if (list.length this.config.failThreshold) { alerts.push({ id: crypto.randomUUID(), type: BRUTE_FORCE, severity: high, srcIp: ev.srcIp, dstIp: ev.dstIp, message: 检测到暴力破解${ev.srcIp} - ${ev.dstIp} 在 ${this.config.windowMs / 1000}s 内失败 ${list.length} 次, timestamp: now, meta: { usernameList: this.extractUsernames(list) }, }); } } else if (ev.action success this.config.successAlert) { // 同源 IP 在此窗口内有过失败记录突然成功判定攻击成功 const prevFailures this.failCount.get(key) ?? []; if (prevFailures.length 0) { alerts.push({ id: crypto.randomUUID(), type: ACCOUNT_TAKEOVER, severity: critical, srcIp: ev.srcIp, dstIp: ev.dstIp, message: 暴力破解疑似成功${ev.srcIp} 在失败 ${prevFailures.length} 次后登录成功, timestamp: now, meta: { username: ev.detail?.username }, }); this.failCount.delete(key); // 告警后重置状态 } } } return alerts; } private extractUsernames(list: Array{ time: number; detail: string }): string[] { const unique new Set(list.map(x x.detail)); return [...unique].slice(0, 20); } }这个检测器里最值得讲的是“失败后成功”的关联逻辑。单纯数失败次数会漏掉一个重要场景攻击者已经撞库成功只是你没察觉。所以检测器在action success时回查该源 IP 在窗口内有没有失败记录有就发ACCOUNT_TAKEOVER告警级别直接拉满到 critical。这个设计在答辩时讲出来导师会认为你考虑了攻击链的闭环。failThreshold建议在演示环境设 5因为模拟脚本不会真的跑几十次请求但真实环境 10 次/分钟已经算严格了要考虑误报。3.3 恶意请求检测规则引擎 正则匹配配置驱动而不是代码驱动第三类检测器针对 Web 攻击比如 SQL 注入、路径穿越、敏感文件探测。这类检测不适合写死在代码里应该做成规则表用 JSON 配置驱动。每条规则包含名称、匹配字段、正则表达式、严重级别。// src/detectors/malicious-request.detector.ts import type { Detector, Alert } from ./detector; import type { SecurityEvent } from ../types/event; export interface MatchRule { name: string; field: keyof SecurityEvent[detail] | path | query; pattern: string; // 正则字符串运行前 new RegExp 编译 severity: low | medium | high; description: string; } export class MaliciousRequestDetector implements Detector { private rules: MatchRule[] []; private compiled: ArrayMatchRule { regex: RegExp } []; constructor(rules: MatchRule[]) { this.setRules(rules); } // 支持运行时热更新规则 setRules(rules: MatchRule[]): void { this.rules rules; this.compiled rules.map(r ({ ...r, regex: new RegExp(r.pattern, i) })); } detect(events: SecurityEvent[]): Alert[] { const alerts: Alert[] []; for (const ev of events) { if (ev.protocol ! http) continue; for (const rule of this.compiled) { // 提取要匹配的字符串 let target ; if (rule.field path) { target String(ev.detail?.path ?? ); } else if (rule.field query) { target String(ev.detail?.query ?? ); } else { target String(ev.detail?.[rule.field] ?? ); } if (rule.regex.test(target)) { alerts.push({ id: crypto.randomUUID(), type: MALICIOUS_REQUEST, severity: rule.severity, srcIp: ev.srcIp, message: 规则命中 [${rule.name}]${rule.description}, timestamp: ev.timestamp, meta: { matched: target.slice(0, 200), rule: rule.name }, }); } } } return alerts; } reset(): void { // 规则检测器是无状态的不需要重置 } }// config/rules.json [ { name: SQL注入尝试, field: query, pattern: (union\\sselect|sleep\\(|benchmark\\(), severity: high, description: 检测常见的SQL注入特征 }, { name: 路径穿越, field: path, pattern: (\\.\\./|\\.\\.\\\\), severity: high, description: 检测目录穿越攻击 }, { name: 敏感文件探测, field: path, pattern: (\\.env|\\.git/|wp-admin|phpmyadmin), severity: medium, description: 检测敏感路径扫描行为 } ]正则规则驱动的核心价值是“运营友好”改规则不需要改代码、不需要重启服务安全管理员直接编辑 JSON 文件即可。setRules方法对外暴露意味着系统可以做一个规则管理接口把“改规则”做成前端页面上的一个表单这就是加分项了。必须提醒的是正则的性能陷阱pattern里不要写灾难性回溯模式比如(a)$否则攻击者构造一个特殊字符串就能把 Node.js 事件循环卡死。课程设计不需要做得太复杂但至少要懂得这个道理。4. 从源码压缩包到跑通演示环境搭建、配置参数与接口自测4.1 初始化 TypeScript 服务端项目tsconfig 里哪些开关必须打开拿到服务端源码压缩包后第一步不是读代码而是先把项目跑起来。解压后先看根目录有没有package.json有就直接npm install。如果源码包是精简过的常见于课程设计可能需要手动补齐依赖。下面这套初始化步骤是 TypeScript Node.js 服务端项目的标配流程# 1. 初始化项目 npm init -y # 2. 安装运行时依赖 npm install express ws dotenv winston # 3. 安装开发期依赖 npm install -D typescript ts-node types/node types/express # 4. 生成 tsconfig.json npx tsc --inittsconfig.json 里这几个开关必须确认否则编译期类型检查形同虚设{ compilerOptions: { target: ES2020, module: commonjs, strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, outDir: ./dist, rootDir: ./src, resolveJsonModule: true }, include: [src/**/*], exclude: [node_modules, dist] }strict: true是最重要的一行。很多课程设计源码为了省事把 strict 关掉结果any满天飞等于没用 TypeScript。答辩时老师问“你的类型安全体现在哪”你能指着 tsconfig 说“全程 strict 模式”——这比任何口头解释都有力。resolveJsonModule是让代码里能直接import rules from ../config/rules.json规则引擎的 JSON 配置就靠它。ts-node负责开发期直接跑 TS 文件不必每次改代码都手动编译。4.2 环境变量与配置参数一个 .env 文件管住所有检测阈值所有检测器的阈值、服务端口、数据库路径都应该通过环境变量下发而不是散落在代码里。新建.env文件格式如下# 服务端口 PORT3000 # 检测引擎批处理参数 BATCH_SIZE100 FLUSH_INTERVAL_MS500 # 端口扫描检测器参数 SCAN_WINDOW_MS10000 SCAN_THRESHOLD20 SCAN_COOLDOWN_MS60000 # 暴力破解检测器参数 BRUTE_WINDOW_MS60000 BRUTE_FAIL_THRESHOLD10 # 告警数据文件SQLite 或 JSON 文件课程设计用 JSON 足够 DATA_FILE./data/alerts.json代码里通过dotenv读取并在启动时把参数注入检测器构造函数import dotenv from dotenv; dotenv.config(); const config { scan: { windowMs: Number(process.env.SCAN_WINDOW_MS) || 10_000, threshold: Number(process.env.SCAN_THRESHOLD) || 20, cooldownMs: Number(process.env.SCAN_COOLDOWN_MS) || 60_000, }, brute: { windowMs: Number(process.env.BRUTE_WINDOW_MS) || 60_000, failThreshold: Number(process.env.BRUTE_FAIL_THRESHOLD) || 10, }, }; const engine new DetectionEngine(); engine.register(port-scan, new PortScanDetector(config.scan)); engine.register(brute-force, new BruteForceDetector(config.brute));参数全部环境变量化的回报在演示当天才能体现评委说“阈值设这么高是不是检测不到”你改一行.env重启服务就能重新演示而不是翻代码改常量。4.3 启动服务并用 curl 完成一次完整的服务端接口测试服务端启动脚本配置在package.json的scripts字段里{ scripts: { dev: ts-node src/index.ts, build: tsc, start: node dist/index.js } }npm run dev服务起来后先用 curl 验证健康检查接口curl http://localhost:3000/health # 期望返回 {status:ok}接下来构造一条正常的 HTTP 请求事件上报给系统验证归一化流程curl -X POST http://localhost:3000/api/events \ -H Content-Type: application/json \ -d { id: evt-001, timestamp: 1718000000000, srcIp: 192.168.1.100, dstIp: 10.0.0.1, dstPort: 8080, protocol: http, action: allow, detail: { path: /api/login, query: , method: POST, authType: login, username: admin } }再用一个带 SQL 注入特征的请求测规则引擎curl -X POST http://localhost:3000/api/events \ -H Content-Type: application/json \ -d { id: evt-002, timestamp: 1718000000001, srcIp: 192.168.1.101, dstIp: 10.0.0.1, dstPort: 8080, protocol: http, action: allow, detail: { path: /api/search, query: keyword1 UNION SELECT username FROM users, method: GET } }然后查告警列表curl http://localhost:3000/api/alerts如果告警列表里出现了MALICIOUS_REQUEST类型、规则名是“SQL注入尝试”的记录说明整条链路已经通了。这组 curl 命令本身就是绝佳的答辩素材——用一个手工构造的恶意请求演示“从上报到告警”的完整过程比打开浏览器点按钮更有说服力。5. 服务端检测系统避坑指南四个高频翻车现场与解法5.1 时间戳格式不统一滑动窗口计算全部错乱现象端口扫描检测器明明访问了几十个端口就是不触发告警或者刚启动服务就疯狂告警。原因上报事件里timestamp有的是2025-06-01 12:00:00字符串有的是Date.now()毫秒数还有的是秒级 Unix 时间戳。检测器里做now - t windowMs时字符串转 number 得到 NaN比较结果恒为 false秒级和毫秒级混用时窗口缩小了 1000 倍。解决入口处统一做一次时间戳规范化任何数据源进来先过这一关。function normalizeTimestamp(input: number | string): number { if (typeof input number) { // 13 位是毫秒10 位是秒统一转成毫秒 return input 1e12 ? input * 1000 : input; } const parsed Date.parse(input); return Number.isNaN(parsed) ? Date.now() : parsed; }这是所有检测器的前置处理没有例外。5.2 同步阻塞导致积压事件丢失检测永远慢半拍现象模拟攻击脚本一次性发 5000 条事件服务端响应越来越慢最后事件队列里的数据全丢了。原因事件上报接口里直接同步执行检测逻辑每条事件的处理时间可能只要 0.1ms但 5000 条累加就是 500ms 的阻塞。期间新请求进不来内存里的队列被不断堆积最终触发内存溢出。解决上报接口只做“接收 入队”检测逻辑在setImmediate或独立的事件循环里异步执行。代码上用第 2 章的批处理引擎模式接口层绝对不跑detect。5.3 TypeScript enum 在 JSON 序列化后变成裸字符串类型守护失效现象规则引擎匹配protocol Protocol.TCP永远为 false但对比字符串tcp却能匹配。原因TypeScript 的enum编译后是双向映射对象但 JSON.parse 出来的数据里字段值是纯字符串不是 enum 实例。Protocol.TCP是数字默认 enum 从 0 开始字符串与数字比较永远不相等。解决优先用const对象加 union 类型替代 enum这是现代 TypeScript 的推荐做法。export const Protocol { TCP: tcp, UDP: udp, HTTP: http, DNS: dns, } as const; export type Protocol typeof Protocol[keyof typeof Protocol];这样Protocol.TCP的值就是字符串tcp与 JSON 数据天然一致且依然有类型提示。5.4 阈值太低导致告警风暴告警列表秒变日志文件现象演示时模拟客户端一启动告警列表瞬间几百条前端大屏全屏飘红。原因threshold设了 5模拟脚本 5 秒内就产生 20 个扫描事件同源 IP 每满 5 个就触发一次告警且没有冷却。解决告警必须做聚合10 秒内的同类告警只保留一条并累计触发次数。实现上就是第 3 章的cooldownMs机制外加一条经验法则——阈值宁可先设高演示时再调低不要一开始设低被误报淹没。这个问题的本质是告警降噪真实环境里没有降噪机制的系统根本没法用安全运营人员会直接关掉你的推送。6. 进阶方向规则热加载、实时推送与可视化对接演示系统跑通后有三个低成本高回报的进阶方向可以让项目从“课程设计”变成“作品集”。第一是规则热加载。现在的规则引擎支持setRules但服务端没有暴露修改接口。加一个POST /api/rules的管理接口把新规则写入 JSON 文件后调用setRules整个检测系统不用重启就能生效。这一项在答辩时展示“动态更新检测策略”效果极好。第二是 WebSocket 实时推送告警。前端大屏用轮询拉告警一秒一刷演示时总觉得卡顿。改用ws库在服务端做一个发布订阅检测引擎每次产生新告警就推送到所有连接的客户端前端可以直接用 TypeScript 收告警——前后端共享类型定义在这一步会有回报。第三是接入可视化系统做流量画像。用 ECharts 的桑基图展示源 IP 到目标 IP 的访问关系、用折线图展示事件量趋势把告警叠加到时间轴上。这正好凑齐“恶意流量可视化检测系统”的完整形态。验证方法上不要手动点接口写一个模拟攻击脚本批量造数据300 条正常登录 30 次失败密码 2 次成功验证暴力破解和撞库成功两条路径再生成 200 个随机目标端口连接验证端口扫描。跑完看三类指标检测准确率、误报率、单批事件处理延迟。延迟在 100ms 以内就算合格。最后说一个我的血泪教训课程设计不要追求“检测算法创新”评委想看到的是完整闭环——数据能进、检测能跑、告警能看、参数能调。把这几件事做扎实比塞一堆看起来高深但没跑通的模型强得多。用 TypeScript 做这件事最大的收益是它逼着你先把数据结构定义清楚而这恰恰是安全系统最不该糊弄的部分。希望帮到你。本文还有配套的精品资源点击获取
返回列表