一、输入Schema与边界type Str = { type: 'string'; min: number; max: number; pattern?: RegExp }
type Num = { type: 'number'; min: number; max: number; integer?: boolean }
type Field = Str | Num
type Schema = { properties: Record<string, Field>; required?: string[] }
二、生成器与变异function randInt(min: number, max: number): number { return Math.floor(Math.random() * (max - min + 1)) + min }
function genStr(spec: Str): string {
const len = randInt(spec.min, spec.max)
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789_-' + "<>\"'&"
let s = ''
for (let i = 0; i < len; i++) s += chars[randInt(0, chars.length - 1)]
if (spec.pattern && !spec.pattern.test(s)) s = s.replace(/[<>"'&]/g, 'a')
return s
}
function genNum(spec: Num): number {
const n = spec.integer ? randInt(spec.min, spec.max) : Math.random() * (spec.max - spec.min) + spec.min
return Math.min(spec.max, Math.max(spec.min, n))
}
function mutateString(s: string): string {
const ops = [
(x: string) => x + "' OR '1'='1",
(x: string) => `<script>alert(1)</script>` + x,
(x: string) => x.slice(0, 1),
(x: string) => x.repeat(10)
]
return ops[randInt(0, ops.length - 1)](s)
}
三、速率限制与重放class RateGate {
windowMs: number
max: number
hits = new Map<string, number[]>()
constructor(windowMs: number, max: number) { this.windowMs = windowMs; this.max = max }
allow(key: string): boolean {
const now = Date.now()
const arr = (this.hits.get(key) || []).filter(t => now - t < this.windowMs)
if (arr.length >= this.max) return false
arr.push(now); this.hits.set(key, arr); return true
}
}
type Case = { input: Record<string, any>; id: string }
class Corpus { items: Case[] = []; add(c: Case) { this.items.push(c) } get(i: number) { return this.items[i] } size() { return this.items.length } }
四、执行器与审计type Req = { path: string; method: string }
type Res = { status: (n: number) => Res; end: (b?: string) => void }
type Target = (input: Record<string, any>, req: Req, res: Res) => void
type Audit = { id: string; caseId: string; route: string; method: string; ok: boolean; timestamp: string }
function nowIso(): string { return new Date().toISOString() }
function run(target: Target, schema: Schema, corpus: Corpus, gate: RateGate, req: Req, res: Res): Audit[] {
const audits: Audit[] = []
for (let i = 0; i < corpus.size(); i++) {
if (!gate.allow(req.path)) break
const c = corpus.get(i)
try { target(c.input, req, res); audits.push({ id: String(Date.now()) + i, caseId: c.id, route: req.path, method: req.method, ok: true, timestamp: nowIso() }) }
catch { audits.push({ id: String(Date.now()) + i, caseId: c.id, route: req.path, method: req.method, ok: false, timestamp: nowIso() }) }
}
return audits
}
五、样例与验收const schema: Schema = { properties: { username: { type: 'string', min: 3, max: 16, pattern: /^[a-z0-9_\-]+$/i }, age: { type: 'number', min: 0, max: 120, integer: true } }, required: ['username'] }
const corpus = new Corpus()
for (let i = 0; i < 50; i++) {
const u = genStr(schema.properties['username'] as Str)
const a = genNum(schema.properties['age'] as Num)
corpus.add({ id: 'case_' + i, input: { username: i % 5 === 0 ? mutateString(u) : u, age: a } })
}
生成策略包含边界值与注入变异;RateGate生效;重放通过`caseId`与输入快照实现。审计包含`route/method/caseId/ok/timestamp`;覆盖统计可基于字段变异率与错误比例。

发表评论 取消回复