achmdfzn/hippocrates

GitHub: achmdfzn/hippocrates

一款 Next.js 安全中间件,通过 Redis 累计威胁评分和蜜罐诱饵路由,在不暴露拦截信号的情况下隐蔽地隔离恶意请求。

Stars: 6 | Forks: 0

# Hippocrates [![npm version](https://img.shields.io/npm/v/hippocrates-middleware)](https://www.npmjs.com/package/hippocrates-middleware) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/e5118779ae020030.svg)](https://github.com/achmdfzn/hippocrates/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/achmdfzn/hippocrates/branch/main/graph/badge.svg)](https://codecov.io/gh/achmdfzn/hippocrates) [![License](https://img.shields.io/github/license/achmdfzn/hippocrates)](https://github.com/achmdfzn/hippocrates/blob/main/LICENSE) [![GitHub Stars](https://img.shields.io/github/stars/achmdfzn/hippocrates)](https://github.com/achmdfzn/hippocrates) Next.js App Router 安全中间件,它将恶意请求路由到诱饵 handler,而不是直接拦截它们。使用基于 Redis 的累计威胁评分系统,覆盖六个检测层。 ``` npm install hippocrates-middleware zod ``` ## 目录 - [工作原理](#how-it-works) - [环境要求](#requirements) - [教程](#tutorial) - [代码库结构](#codebase-structure) - [关联仓库](#pairing-the-repo) - [防御层](#defense-layers) - [配置](#configuration) - [插件系统](#plugin-system) - [事件钩子](#event-hooks) - [统计跟踪](#stats-tracking) - [ML 引擎 (Python Sidecar)](#ml-engine-python-sidecar) - [许可证](#license) ## 工作原理 每个传入的请求都会经过检测层。每一层都会为存储在 Redis 中的 IP 累计威胁评分增加分数。如果分数超过阈值,该请求将被路由到诱饵生成器,而不是真实的 handler。诱饵会返回带有虚假数据的 200 OK 状态码。调用者永远不会看到 403 或 429,并且不会收到任何被检测到的信号。 ``` Incoming Request | v L-1 Allowlist? ---- YES --> Forward to handler (skip all checks) | NO v L0 Pre-flight score check ---- score >= threshold? ---- YES --> HONEYPOT (200 OK, fake data) | NO v Pre-body analyzers: L1 Timing, L2 Velocity, L3 UA, L4 Headers | score >= threshold? |-- YES --> HONEYPOT | NO v Body parsing + Post-body analyzers: L5 Obfuscation, L6 Schema | score >= threshold? |-- YES --> HONEYPOT | NO v Forward clean request to real handler ``` ## 环境要求 - Node.js >= 18 - Next.js >= 14 (peer dependency) - Zod >= 3.22 (peer dependency) - Redis client (Upstash, ioredis 或兼容客户端) ## 教程 本教程将从头开始演示如何保护 Next.js App Router endpoint。 ### 1. 创建或打开一个 Next.js 项目 ``` npx create-next-app@latest my-app --typescript cd my-app ``` ### 2. 安装依赖 ``` npm install hippocrates-middleware zod npm install @upstash/redis # or your Redis client of choice ``` ### 3. 设置路由 创建 `app/api/users/route.ts`: ``` import { NextRequest, NextResponse } from "next/server"; import { Redis } from "@upstash/redis"; import { withHippocrates, z } from "hippocrates-middleware"; const redis = new Redis({ url: process.env.UPSTASH_REDIS_REST_URL!, token: process.env.UPSTASH_REDIS_REST_TOKEN!, }); // Schemas must use .strict() -- extra fields trigger a violation const CreateUserSchema = z.object({ name: z.string().min(1), email: z.string().email(), }).strict(); async function handler(req: NextRequest): Promise { const body = await req.json(); // body is already validated by the middleware return NextResponse.json({ id: crypto.randomUUID(), ...body }); } export const POST = withHippocrates(handler, CreateUserSchema, redis); ``` ### 4. 添加环境变量 创建 `.env.local`: ``` UPSTASH_REDIS_REST_URL=https://your-redis-url.upstash.io UPSTASH_REDIS_REST_TOKEN=your-token ``` ### 5. 运行 ``` npm run dev ``` 发送一个有效的请求: ``` curl -X POST http://localhost:3000/api/users \ -H "Content-Type: application/json" \ -d '{"name": "Alice", "email": "alice@example.com"}' # 响应:200 OK 以及 { id, name, email } ``` 中间件会根据 Zod schema 验证请求体。如果请求体有效,它将放行至 `handler`。 ### 6. 触发蜜罐 发送一个带有额外字段的请求: ``` curl -X POST http://localhost:3000/api/users \ -H "Content-Type: application/json" \ -d '{"name": "Alice", "email": "alice@example.com", "role": "admin"}' ``` `.strict()` schema 会拒绝未知字段。该请求将被路由到诱饵生成器,你会收到带有虚假数据的 200 OK 响应。 在短时间内从同一 IP 发送过多请求,或者使用带有可疑 User-Agent 的工具: ``` curl -X POST http://localhost:3000/api/users \ -H "Content-Type: application/json" \ -H "User-Agent: python-requests/2.31.0" \ -d '{"name": "Bob", "email": "bob@example.com"}' ``` UA 特征 `python-requests` 会触发 L3。在 10 秒内重复此操作 10 次以上,L2 频率跟踪将增加更多分数。一旦超过阈值,你就会进入蜜罐。 ### 7. 使用自定义配置 ``` export const POST = withHippocrates(handler, CreateUserSchema, redis, { preset: "strict", allowlist: { ips: ["10.0.0.0/8", "127.0.0.1"] }, bodyLimit: { maxBytes: 524288, enabled: true }, scoring: { impossibleTiming: 35, suspiciousUserAgent: 25, }, hooks: { onHoneypot: (event) => { console.log(`Honeypot served to ${event.ip}`); }, }, }); ``` ## 代码库结构 ``` src/ index.ts # Entry point -- withHippocrates() HOF, re-exports engine/ types.ts # Type definitions (RedisClient, HippocratesConfig, etc.) constants.ts # Default values, UA patterns, obfuscation patterns analyzers.ts # Built-in analyzer plugin placeholders (L1-L6) threat-score-engine.ts # Redis-backed scoring engine with circuit breaker system/ pipeline.ts # Request processing pipeline honeypot.ts # Decoy response generator validator.ts # Zod validation helpers (validatePayload, ensureStrict) plugins/ ml-engine.ts # Python sidecar AnalyzerPlugin utils/ ip.ts # IPv6 normalization and client IP resolution __tests__/ helpers.ts # Test mocks ip.test.ts # 30 tests threat-score-engine.test.ts # 45 tests validate-payload.test.ts # 8 tests decoy.test.ts # 11 tests with-hippocrates.test.ts # 51 tests (integration) ensure-strict.test.ts # 25 tests redis-degradation.test.ts # 6 tests stats.test.ts # 5 tests stats-integration.test.ts # 13 tests ml-engine-integration.test.ts # 15 tests engine-python/ app/ main.py # FastAPI application config.py # Environment-based settings models.py # Request/response models analyzers/ # ML detection modules prompt_injection.py obfuscation_advanced.py content_risk.py tests/ test_analyzers.py # 31 tests test_api.py # 8 tests Dockerfile requirements.txt example/ app/api/data/route.ts # Reference implementation ``` ## 关联仓库 ``` git clone https://github.com/achmdfzn/hippocrates.git cd hippocrates npm install npm run build npm test # 209 tests npm run typecheck # tsc --noEmit, zero errors npm run lint # ESLint, zero errors ``` 要运行包含 Python ML 引擎的完整技术栈: ``` # 需要:Docker、Python 3.12+ docker compose up -d # Redis + ML engine npm test # TS tests (209) cd engine-python && pytest -v # Python tests (39) ``` 开发工作流: ``` npm run dev # tsup --watch (recompiles on source changes) npm run test:watch # Vitest watch (reruns tests on changes) ``` CI pipeline (GitHub Actions): ``` quality (Node 18/20/22): lint -> typecheck -> test -> build docker: build ML engine image -> healthcheck ``` ## 防御层 | 层级 | 检查项 | 分数 | 条件 | |-------|-------|--------|-----------| | L-1 | IP 白名单 | 0 (全部绕过) | IP 在白名单配置中 | | L0 | 预检分数 | 立即触发蜜罐 | 现有 Redis 分数 >= 阈值 | | L1 | 请求时间 | +25 | 间隔 < 50ms | | L2 | 请求频率 | +40 | 突发请求 > 15 次 / 10s 窗口 | | L3 | User-Agent | +15 | 可疑或缺失 UA | | L4 | HTTP 标头 | +15 | 缺失或使用通配符的 Accept 等 | | L5 | Payload 混淆 | +100 | Base64、十六进制、URL 编码、Unicode | | L6 | Zod schema | +100 | .strict() 违规 | L5 和 L6 在检测到时会立即将分数提升至 100。 UA 特征 (40+ 种):LLM SDK (anthropic-sdk, openai-node, langchain),HTTP 库 (python-requests, curl, axios),浏览器自动化工具 (playwright, puppeteer),2026 AI agent (claude, cursor, perplexitybot, opencode)。 混淆特征:Base64 (>=24 字符),十六进制编码 (>=16 字符),URL 编码 (连续 5+ 字符),Unicode 转义,HTML 实体。 ## 配置 ``` interface HippocratesConfig { preset?: "strict" | "moderate" | "relaxed"; threatScoreThreshold?: number; // Default: 65 velocityWindowMs?: number; // Default: 10000 velocityMaxRequests?: number; // Default: 15 threatTtlSeconds?: number; // Default: 3600 scoring?: Partial; decoyGenerator?: (req: NextRequest) => Record; debugMode?: boolean; // Default: false plugins?: AnalyzerPlugin[]; hooks?: HippocratesHooks; allowlist?: { ips: string[] }; bodyLimit?: { maxBytes: number; enabled: boolean }; methodThresholds?: Partial>; violationMessages?: Record Record>; statsTracker?: StatsTracker; } ``` 预设值: | 预设 | 阈值 | 最大频率 | 窗口期 | |--------|-----------|-------------|--------| | strict | 40 | 10 次请求 | 10s | | moderate | 65 | 15 次请求 | 10s | | relaxed | 80 | 30 次请求 | 30s | Redis 键结构: | 键 | 用途 | TTL | |-----|---------|-----| | `hc:s:{ip}` | 威胁分数 (0-100) | `threatTtlSeconds` | | `hc:t:{ip}` | 请求时间戳 (频率) | `windowMs + 10s` | | `hc:l:{ip}` | 最后访问时间戳 (时间) | 300s | 自定义违规消息: ``` export const POST = withHippocrates(handler, schema, redis, { violationMessages: { obfuscation: (violation) => ({ error: "invalid_payload_format", code: "OBFUSCATION_DETECTED", }), schema: (violation) => ({ error: "validation_failed", }), }, }); ``` 键是违规类型的前缀 (obfuscation、schema、ua、velocity、timing、header)。该函数接收完整的违规标签字符串,并返回一个与诱饵响应合并的对象。 ## 插件系统 通过 AnalyzerPlugin 接口实现自定义检测逻辑: ``` import { type AnalyzerPlugin } from "hippocrates-middleware"; const geoBlock: AnalyzerPlugin = { name: "geo_block", phase: "pre-body", // "pre-body" | "post-body" priority: 50, // Lower runs first. Default: 100 analyze(req, ctx) { const country = req.headers.get("x-country"); if (country === "blocked") { return { score: 50, tags: ["geo:blocked"] }; } return { score: 0, tags: [] }; }, }; export const POST = withHippocrates(handler, schema, redis, { plugins: [geoBlock], }); ``` 插件在每个阶段内按 priority 升序排序。priority 相同则保持注册顺序。 其他用例示例: **频率限制模拟 — 在不拦截的情况下为高频请求增加分数:** ``` const rateMimic: AnalyzerPlugin = { name: "rate_mimic", phase: "pre-body", priority: 90, analyze(req, ctx) { const freq = parseInt(req.headers.get("x-request-frequency") ?? "0"); if (freq > 100) return { score: 30, tags: ["rate:high"] }; if (freq > 50) return { score: 15, tags: ["rate:medium"] }; return { score: 0, tags: [] }; }, }; ``` **已知爬虫检测 — 匹配特定路由的 URL 模式:** ``` const scraperDetect: AnalyzerPlugin = { name: "scraper_detect", phase: "pre-body", priority: 40, analyze(req, ctx) { const url = req.nextUrl.pathname; const sensitivePaths = ["/api/users", "/api/orders", "/api/admin"]; if (sensitivePaths.some((p) => url.startsWith(p))) { const ua = req.headers.get("user-agent") ?? ""; if (ua.includes("python-requests") || ua.includes("axios")) { return { score: 25, tags: ["scraper:sensitive"] }; } } return { score: 0, tags: [] }; }, }; ``` ## 事件钩子 ``` export const POST = withHippocrates(handler, schema, redis, { hooks: { onViolation: (event) => { console.log(`${event.ip} - ${event.violations}`); }, onPass: (event) => { metrics.recordPass(event.ip, event.score); }, onHoneypot: (event) => { alertService.notify(`Honeypot served to ${event.ip}`); }, }, }); ``` ## 统计跟踪 可通过 `ThreatScoreEngine.getStats()` 访问的内存计数器。传入自定义的 `StatsTracker` 以进行外部持久化: ``` import { type StatsTracker } from "hippocrates-middleware"; const tracker: StatsTracker = { increment(counter) { console.log(`Event: ${counter}`); }, getStats() { return { totalRequests: 0, blockedByPreflight: 0, /* ... */ }; }, reset() {}, }; ``` 警告:在 Serverless 环境 (Vercel Edge, AWS Lambda) 中,每次冷启动都会创建一个新的 `ThreatScoreEngine` 实例 —— 统计数据在每次调用时都会重置。请使用可持久化到外部存储的自定义 `StatsTracker` 以进行生产环境监控。 可用计数器:`totalRequests`、`blockedByPreflight`、`blockedByTiming`、`blockedByVelocity`、`blockedByObfuscation`、`blockedBySchema`、`passedToHandler`、`honeypotServed`、`redisErrors`。 基于 Redis 的 StatsTracker 示例: ``` import { type StatsTracker } from "hippocrates-middleware"; import { Redis } from "@upstash/redis"; function createRedisStatsTracker(redis: Redis): StatsTracker { const key = "hc:stats"; return { increment(counter) { redis.hincrby(key, counter, 1).catch(() => {}); }, async getStats() { const data = await redis.hgetall>(key); if (!data) { return { totalRequests: 0, blockedByPreflight: 0, blockedByTiming: 0, blockedByVelocity: 0, blockedByObfuscation: 0, blockedBySchema: 0, passedToHandler: 0, honeypotServed: 0, redisErrors: 0, }; } return Object.fromEntries( Object.entries(data).map(([k, v]) => [k, Number(v)]), ) as SecurityStats; }, reset() { redis.del(key).catch(() => {}); }, }; } ``` 将其传递给 `withHippocrates` 以在冷启动间持久化统计数据: ``` export const POST = withHippocrates(handler, schema, redis, { statsTracker: createRedisStatsTracker(redis), }); ``` ## ML 引擎 (Python Sidecar) 可选的基于 ML 的检测:prompt 注入、高级混淆、内容风险评分 (SQLi、XSS、路径遍历、命令注入)。运行在 Python FastAPI sidecar 中。 ``` docker compose up -d ``` ``` import { mlEnginePlugin } from "hippocrates-middleware"; export const POST = withHippocrates(handler, schema, redis, { plugins: [mlEnginePlugin({ baseUrl: "http://ml-engine:8000", timeoutMs: 3000, minScoreThreshold: 10, })], }); ``` 如果 ML 引擎不可达,它将返回分数 0 并带有 `ml-engine-unreachable` 标签。该插件有自己的熔断器:连续 3 次失败将触发 30 秒的冷却时间。 ML 引擎配置选项: | 选项 | 默认值 | 描述 | |--------|---------|-------------| | `baseUrl` | `http://localhost:8000` | ML 引擎 endpoint | | `timeoutMs` | `3000` | 请求超时时间 | | `minScoreThreshold` | `10` | 贡献评分的最低 ML 分数 | | `maxRetries` | `1` | 降级前的重试次数 | | `circuitBreakerCooldownMs` | `30000` | 达到最大失败次数后的冷却时间 | | `maxConsecutiveFailures` | `3` | 触发熔断前的失败次数 | ## 许可证 MIT (c) achmdfzn
标签:AppImage, CISA项目, MITM代理, Web安全, Web应用防火墙, 威胁评分, 安全中间件, 密码管理, 搜索引擎查询, 自动化攻击, 蓝队分析, 蜜罐技术, 请求拦截, 逆向工具