crumrine/web-tarpit
GitHub: crumrine/web-tarpit
一个零依赖的 JavaScript Web 蜜罐,通过伪造 WordPress 页面和环境文件并以极慢速率响应,消耗恶意 Bot 的扫描资源并记录其行为。
Stars: 16 | Forks: 0
# web-tarpit
适用于任何 JavaScript 服务器的 Bot 陷阱。通过伪造的 WordPress 页面、蜜罐凭据和缓慢的响应流来消耗漏洞扫描器的时间。
零依赖。单次导入。适用于所有支持 Web 标准 `Request`/`Response` API 的环境。
## 安装
```
npm install web-tarpit
```
## 使用方法
### Cloudflare Workers
```
import { tarpit } from 'web-tarpit';
export default {
async fetch(request, env, ctx) {
const trap = tarpit(request, { ctx });
if (trap) return trap;
return new Response('Hello world');
}
};
```
### Hono
```
import { Hono } from 'hono';
import { tarpit } from 'web-tarpit';
const app = new Hono();
app.use('*', async (c, next) => {
const trap = tarpit(c.req.raw);
if (trap) return trap;
await next();
});
app.get('/', (c) => c.text('Hello'));
export default app;
```
### Next.js Middleware
```
// middleware.js
import { tarpit } from 'web-tarpit';
export function middleware(request) {
const trap = tarpit(request);
if (trap) return trap;
}
export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'] };
```
### Deno / Bun
```
import { tarpit } from 'web-tarpit';
Deno.serve((request) => {
const trap = tarpit(request);
if (trap) return trap;
return new Response('Hello');
});
```
### Express
```
import express from 'express';
import { expressTarpit } from 'web-tarpit/adapters';
const app = express();
app.use(expressTarpit());
app.get('/', (req, res) => res.send('Hello'));
app.listen(3000);
```
### Node.js HTTP
```
import { createServer } from 'http';
import { nodeTarpit } from 'web-tarpit/adapters';
const trap = nodeTarpit();
createServer((req, res) => {
if (trap(req, res)) return; // bot trapped
res.end('Hello');
}).listen(3000);
```
## 功能说明
每个 Web 服务器都会遭到 Bot 的扫描,寻找 WordPress 漏洞、暴露的 `.env` 文件以及管理面板。通常你会返回 404,然后它们会在几毫秒内离开。这个模块会让它们为扫描你而后悔。
| 路径 | Bot 获取到的内容 |
|---|---|
| `/wp-login.php` | 像素级还原的 WordPress 6.7.2 登录页。捕获凭据,每次尝试等待 5-15 秒。 |
| `/wp-admin/*` | 无限的管理面板迷宫。包含 20 多个可点击的页面。 |
| `/.env*` | 缓慢发送伪造的 AWS 密钥、Stripe 密钥和数据库密码。每次下载约 80 秒。 |
| `/.git/*` | 缓慢发送伪造的 git 配置。 |
| `/xmlrpc.php` | 缓慢发送 XML-RPC 错误。开启蜜罐模式后会解析 POST 请求,并使用伪造的管理员成功信息污染暴力破解数据库 —— 参见 [XML-RPC 蜜罐模式](#xml-rpc-honeypot-mode-opt-in)。 |
| `/phpmyadmin/`、`/admin/`、`/login` | 缓慢发送带有 IP 警告的“拒绝访问”提示。 |
| `/shell.php`、`*.sql`、`*.bak` | 缓慢发送“已记录违规行为”的消息。 |
合法请求会原封不动地通过 —— 此检查对正常流量增加的开销为零。
## 日志记录
传入一个 `onTrap` 回调来记录每个被捕获的请求:
```
tarpit(request, {
onTrap: (type, path, ip, request, data) => {
console.log(`[tarpit] ${type} ${path} from ${ip}`);
}
});
```
默认(`'fault'`)模式下的事件类型包括:`login-page`、`login`、`admin`、`env`、`git`、`wp-probe`、`probe`、`xmlrpc`。蜜罐模式(见下文)增加了 `xmlrpc-bruteforce`、`xmlrpc-multicall`、`xmlrpc-pingback` 和 `xmlrpc-listmethods`。
`data` 参数在 `login` 事件中承载表单解码后的值,在 `xmlrpc-*` 事件中承载解析后的 XML-RPC 详情(方法名、捕获的凭据、multicall 计数、pingback 目标 URL)。**注意:`login` 和 `xmlrpc-bruteforce` 事件包含明文凭据。**如果你将它们持久化存储,你的存储将成为一个凭据数据库。如果你不想这样,请对密码字段进行哈希处理。
## XML-RPC 蜜罐模式(可选启用)
`/xmlrpc.php` 是现实世界中最常遭到攻击的路径。WordPress 暴力破解工具利用它将数百次凭据尝试打包进单个 HTTP 请求中,攻击者也利用它通过 `pingback.ping` 将存在漏洞的服务器变成 SSRF / DDoS 反射器。设置 `xmlrpcMode: 'honeypot'` 可将此路径变成一个主动陷阱,它会解析请求并进行欺骗响应:
```
tarpit(request, {
xmlrpcMode: 'honeypot',
ctx,
onTrap: (type, path, ip, request, data) => { /* log to D1, etc. */ },
});
```
| 方法 | 蜜罐回复 |
|---|---|
| `wp.getUsersBlogs`、`wp.getProfile`、`wp.getOptions`、`wp.getPosts`、`wp.getUsers`、`wp.getUser`、`wp.getPages`、`wp.getPage`、`metaWeblog.*`、`blogger.*` | 伪造 `isAdmin: true` 成功。攻击者尝试的每一对凭据看起来都“有效” —— 从而用垃圾数据污染暴力破解数据库。 |
| `system.multicall` | 根据内部调用次数返回对应大小的成功数组,上限为 1..200。 |
| `pingback.*` | 始终返回错误。永远不会返回成功 —— 拒绝被用作 SSRF 反射器。 |
| `system.listMethods` | 缓慢发送包含约 80 个伪造的 WordPress 方法的列表。 |
| 其他任何内容 | 缓慢发送错误。 |
默认模式(`xmlrpcMode: 'fault'`,即 1.0 版本的行为)对每个 `/xmlrpc.php` 请求返回缓慢发送的错误,并触发一次 `xmlrpc` 事件。
对于使用 D1 的 Cloudflare Workers,传入 `ctx` 并记录到数据库:
```
tarpit(request, {
ctx,
onTrap: (type, path, ip, request) => {
return env.TARPIT_DB.prepare(
"INSERT INTO tarpit_log (site, type, path, ip, ua, ts) VALUES (?, ?, ?, ?, ?, datetime('now'))"
).bind(
new URL(request.url).hostname, type, path, ip,
request.headers.get('user-agent') || ''
).run();
}
});
```
D1 的表结构定义在 `schema.sql` 中。配套的分析仪表板位于 `dashboard/` 目录中。
## API
### `tarpit(request, options?)`
| 参数 | 类型 | 描述 |
|---|---|---|
| `request` | `Request` | Web 标准 Request 对象 |
| `options.onTrap` | `function` | 回调函数:`(type, path, ip, request, data?) => void\|Promise` |
| `options.ctx` | `object` | 包含 `waitUntil()` 的执行上下文(Cloudflare Workers) |
| `options.xmlrpcMode` | `'fault' \| 'honeypot'` | 默认为 `'fault'`。`'honeypot'` 启用识别方法的 XML-RPC 回复(见上文)。 |
| `options.slowDripMs` | `number` | 每次发送数据块的延迟覆盖。省略则使用默认的 100..500ms 抖动。设为 `0` 可完全禁用缓慢发送(仅用于测试)。 |
如果路径是 Bot 探测,则返回 `Response`;如果是合法请求,则返回 `null`。
### `isBotPath(path)`
检查 URL 路径是否会触发陷阱。返回 `boolean`。
```
import { isBotPath } from 'web-tarpit';
if (isBotPath('/wp-login.php')) { /* ... */ }
```
### `expressTarpit(options?)` (来自 `web-tarpit/adapters`)
Express/Connect 中间件。选项与 `tarpit()` 相同。
### `nodeTarpit(options?)` (来自 `web-tarpit/adapters`)
为 Node.js `http.createServer` 返回 `(req, res) => boolean`。
## 慢速发送原理
响应以 3 字节的数据块进行流式传输,每次间隔 100-500ms 的随机延迟。期望快速响应的扫描器会在数据缓慢流入时保持连接打开。
对于一个 1KB 的伪造 `.env` 文件:大约 330 个数据块,平均每个约 250ms = 每次扫描大约 **80 秒**。
响应头包含 `X-Powered-By: PHP/8.2.13` 和 `Server: Apache/2.4.57`,以让 Bot 相信它找到了一个真实的 PHP 应用程序。
## 仪表板(可选)

`dashboard/` 目录包含一个独立的 Cloudflare Worker,它从 D1 读取数据并提供一个分析仪表板,展示陷阱统计信息、攻击类型、Top Bot IP 以及 30 天的活动图表。有关完整的部署说明,请参阅 [`dashboard/README.md`](dashboard/README.md)。
## 构建工具
由 [Brian Crumrine](https://github.com/crumrine) 使用 [Claude Code](https://claude.com/claude-code) 设计并构建。
## 许可证
MIT
标签:AppImage, Bot陷阱, Bun, CISA项目, CMS安全, Deno, Express, GNU通用公共许可证, Hono, JavaScript, MITM代理, Node.js, Request/Response, WAF, Web应用防火墙, Web标准, WordPress伪装, 中间件, 密码管理, 恶意爬虫防御, 数据可视化, 欺骗攻击者, 漏洞扫描防御, 程序员工具, 缓慢响应, 网络安全, 自定义脚本, 蜜罐, 证书利用, 隐私保护, 零依赖