duncanschwindt-code/website-risk-checker
GitHub: duncanschwindt-code/website-risk-checker
一个基于多源威胁情报的网站风险检测 Web 应用,通过被动查询和透明评分为用户提供 URL 安全与声誉参考。
Stars: 0 | Forks: 0
# 网站风险检测器
Website Risk Checker 是一个与 **Teens Against Scams** 相关的教育类 Web 应用程序。访客可以输入一个公开可访问的网站 URL,并通过配置的威胁情报查询和被动技术检查,获得对有限的、可观察风险指标的仔细评估。
自动化结果可能不完整、过时或不正确。低分不能保证网站是安全的,高分也不能证明存在欺诈、违法、恶意意图、所有权或犯罪行为。
## 截图

在发布前,请将此占位符替换为已批准的部署截图。不要包含真实的 API 密钥、私有 URL、活跃的恶意 URL 或个人信息。
## 首个版本的功能
- 仅接受公开的 `http` 和 `https` 地址。
- 在显示、记录、缓存或进行提供商查询之前,移除 URL 查询字符串和片段。
- 拒绝嵌入式凭据、内部名称、私有/保留地址、非标准端口和不安全的重定向。
- 在连接目标之前重新解析并验证 DNS,然后锁定已验证的地址。
- 使用有限的 `HEAD` 请求和可选的 TLS 握手;它不执行页面 JavaScript 或下载页面内容。
- 在一个 TypeScript 接口背后规范化提供商结果。
- 使提供商故障、缺失密钥、过期结果和配额耗尽不对评分产生影响。
- 将扫描结果保留在浏览器标签页的会话存储中,而不是公共或服务器端历史记录中。
- 区分实时模式和演示模式;演示案例使用保留域名和本地固定数据。
- 在
[`config/scoring-rules.json`](config/scoring-rules.json) 发布透明、带版本的评分文件。
- 包含一个私密的纠正邮件工作流,该工作流会生成一个参考编号而不存储表单。
它是一个声誉和风险指标工具——而不是漏洞扫描器。它从不执行端口扫描、登录尝试、表单提交、目录发现、CAPTCHA 绕过、漏洞测试、文件下载、恶意软件执行、对提交网站的浏览器自动化操作,或访问控制绕过。
## 提供商合规性快照
该表是工程记录,而非法律建议。条款和配额可能会发生变化。每位运营者在启用提供商之前以及此后至少每 90 天必须审查链接的官方页面。以下审查于 **2026-07-30** 执行。
| 提供商 | 用途 | 需要免费密钥 | 非商业限制 | 典型配额(2026-07-30 验证) | URL 提交行为 | 隐私关注 | 默认启用 | 官方文档 | 最后验证时间 |
| --------------------- | -------------------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| Google Safe Browsing | 已知的社交工程、恶意软件和不受欢迎软件的 URL 匹配 | 是 | 是;免费的 Safe Browsing API 仅限非商业用途 | 默认项目配额;在 Google Cloud Console 中检查当前分配 | 仅查询;从不请求新扫描 | Google 声明提交的 URL 和相关数据可能会被使用和共享 | 否 | [v5 参考](https://developers.google.com/safe-browsing/reference), [条款](https://developers.google.com/safe-browsing/terms) | 2026-07-30 |
| URLhaus | 已知的恶意软件分发 URL | 是 | 社区合理使用;商业或营利需求可能需要付费的增强访问权限 | 合理使用;固定的单次查询配额未公开承诺 | 仅查询;不提交恶意软件 URL | 披露了经编辑的查询 URL;社区数据有其自身的条款 | 否 | [社区 API](https://urlhaus.abuse.ch/api/) | 2026-07-30 |
| PhishTank | 社区钓鱼数据库 | 实际速率限制需要 | 官方条款允许商业 API 数据使用 | 响应头中返回的动态小时限制;HTTP 509 表示超过限制 | 仅查询;不提交报告 | 披露了经编辑的查询 URL;社区提交可能包含错误 | 否 | [API](https://phishtank.org/api_info.php), [条款](https://phishtank.org/terms.php) | 2026-07-30 |
| LevelBlue Labs OTX | 社区威胁情报脉冲 | 是 | 是;OTX 对终端用户免费用于非商业用途 | 未找到固定的公开数量;监控当前账户条款和响应头 | 仅指标查询;不提交内容 | OTX 条款允许保留、使用和分发提交的内容;本项目避免使用提交接口 | 否 | [DirectConnect](https://otx.alienvault.com/api), [OTX EULA](https://www.levelblue.com/legal/otx-eula-terms) | 2026-07-30 |
| VirusTotal Public API | 现有的聚合 URL 分析报告 | 是 | 是;Public API 仅限非商业用途,不适用于业务工作流 | 4 次请求/分钟,每天 500 次 | 仅查询现有报告;不重新扫描 URL,不上传文件 | 请求了 URL 标识符;新提交将被共享,因此已禁用 | 否 | [Public vs Premium](https://docs.virustotal.com/reference/public-vs-premium-api), [URL 报告](https://docs.virustotal.com/reference/url-info) | 2026-07-30 |
完整的机器可读审查位于
[`config/provider-compliance.json`](config/provider-compliance.json)。它记录了每个适配器的署名、
保留、缓存、提交隐私、审查日期和运营者备注。
### 非商业用途警告
`PROJECT_USE_MODE=noncommercial` 是默认设置。Google Safe Browsing、OTX 和 VirusTotal Public API
仅限于非商业用途。对于商业或营利用途,URLhaus 社区访问可能需要商业协议。
受限制的适配器拒绝商业模式。
添加广告、付费订阅、付费访问、赞助安排、数据销售或其他收入可能会改变资格,即使项目仍
具有教育或非营利性质。
在任何商业化之前:
1. 禁用受限制的适配器;
2. 直接从每个提供商获取书面许可或适当的套餐;
3. 审查隐私、署名和再分发义务;
4. 更新合规文件和公开披露。
应用程序永远不会自动切换到付费提供商或规避限制。
## 架构
```
Browser form
│ public URL only; warning shown before submit
▼
Next.js route handler ── application rate limit + same-origin check
│
├── normalize and redact ── remove query/fragment; reject credentials/ports
│
├── DNS safety gate ── reject private/reserved targets
│
├── passive checker ── DNS recheck + pinned HEAD + redirect validation + TLS
│
└── provider adapters ── fixed official endpoints; lookup only; bounded JSON
│
▼
normalized evidence ── transparent scoring ── device-local result page
```
有关安全边界和权衡,请参阅
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) 和
[`docs/THREAT_MODEL.md`](docs/THREAT_MODEL.md)。
## 仓库结构
```
app/ Next.js pages and server route handlers
components/ Accessible UI components
config/ Scoring and provider compliance records
docs/ Architecture, deployment, threat model, checklists
lib/analysis/ Local heuristics, orchestration, transparent scoring
lib/providers/ Independent provider adapters and schemas
lib/security/ SSRF defenses, rate limits, redaction, bounded requests
tests/ Unit, integration, fixtures, and Playwright tests
.github/ CI, CodeQL, Dependabot, templates, policy files
```
初始的隐私最小化版本不需要数据库,因此有意不包含 Prisma 和 SQLite。如果以后添加持久化的纠正存储,
请仅在本地开发中使用带有 SQLite 的 Prisma,并为部署的环境选择生产级的托管数据库。在启用存储之前,
请记录保留、加密、删除、授权、迁移和法律依据。
## 本地设置
要求:
- Node.js 24 或更高版本
- pnpm 11 或更高版本(推荐使用 Corepack)
- 演示模式或测试不需要真实的提供商密钥
```
git clone https://github.com/YOUR-ORG/website-risk-checker.git
cd website-risk-checker
corepack enable
pnpm install --frozen-lockfile
cp .env.example .env
pnpm dev
```
打开 [http://localhost:3000](http://localhost:3000)。要进行完全本地、无网络的产品
演示,请在 `.env` 中设置 `APP_MODE=demo`。
### 环境变量
| 变量 | 是否必需 | 用途 |
| ---------------------------------- | -------------------- | --------------------------------------------------------------------------- |
| `APP_MODE` | 是 | `live` 或 `demo`;demo 仅接受内置示例案例 |
| `PROJECT_USE_MODE` | 是 | `noncommercial` 或 `commercial`;受限适配器拒绝商业模式 |
| `APP_BASE_URL` | 生产环境 | 用于同源检查和元数据的精确公共源 |
| `ENABLE_*` | 每个提供商 | 对每个提供商明确选择启用;默认均为 `false` |
| `*_API_KEY` / `URLHAUS_AUTH_KEY` | 每个启用的提供商 | 仅服务器端凭据;切勿以 `NEXT_PUBLIC_` 作为前缀 |
| `STRICT_PROVIDER_TERMS` | 推荐 | 在严格模式下拒绝逾期的提供商 |
| `PROVIDER_REVIEW_MAX_AGE_DAYS` | 否 | 警告前的最大审查间隔;默认为 90 天 |
| `APP_RATE_LIMIT_*` | 是 | 实例级防滥用限制;多实例生产环境请使用共享存储 |
| `PROVIDER_MAX_RETRIES` | 否 | 针对 timeout、网络故障和 HTTP 5xx 的有限重试次数;默认为 1 |
| `PROVIDER_RETRY_BASE_MS` | 否 | 初始指数退避延迟;默认为 250 毫秒 |
| `TRUST_PROXY` | 视生产环境而定 | 仅在配置的可信代理后信任 `X-Forwarded-For` |
| `RATE_LIMIT_HASH_SECRET` | 生产环境 | 至少 32 个随机字符,用于 HMAC 短期速率限制密钥 |
| `CORRECTION_EMAIL` | 发布前 | 纠正工作流使用的私密收件箱 |
| `PRIVACY_EMAIL` / `SECURITY_EMAIL` | 发布前 | 私密运营者联系方式 |
| `LEGAL_CONTACT` | 发布前 | 运营者提供的法律联系信息 |
请审查 [`.env.example`](.env.example) 中的每个值。切勿提交 `.env`。
## 获取免费访问权限
仅使用官方提供商页面。构建、测试或运行演示模式不需要密钥。
- **Google Safe Browsing:** 请遵循官方
[入门指南](https://developers.google.com/safe-browsing/v4/get-started) 和当前的
[v5 参考](https://developers.google.com/safe-browsing/reference)。在启用前确认非商业资格和当前配额。
- **URLhaus:** 通过
[官方社区 API 页面](https://urlhaus.abuse.ch/api/) 创建免费的 Auth-Key。确认合理使用资格。
- **PhishTank:** 完成免费注册并获取 [官方 FAQ](https://phishtank.org/faq.php) 中描述的应用程序密钥。请尊重速率限制响应头。
- **OTX:** 创建 OTX 账户并从
[官方 API 页面](https://otx.alienvault.com/api) 获取 DirectConnect 密钥。确认非商业资格。
- **VirusTotal:** 获取 [入门](https://docs.virustotal.com/reference/getting-started) 中描述的 Community API 密钥。Public API 不能用于商业目的,
且不能通过跨账户来规避限制。
不要为了满足此仓库而输入信用卡、激活付费试用或接受付费套餐。如果提供商的免费途径或资格发生变化,
请保持适配器禁用并更新合规记录。提供商的定价和注册要求可能随时更改。
## 实时模式和演示模式
### 实时模式
`APP_MODE=live` 接受公开 URL,执行本地安全闸门,列出每个提供商状态,
并使用真实时间戳。缺失密钥将返回 `NOT_CONFIGURED`;它绝不会触发虚假结果或降低评分。
### 演示模式
`APP_MODE=demo`:
- 在每个页面上显示持久的模拟数据横幅;
- 拦截 `/api/analyze`;
- 仅接受 `/api/demo` 处的内置案例 ID;
- 使用保留的 `.test` 名称和模拟提供商数据;
- 不执行实时提供商或目标请求。
`/demo` 页面在实时部署中也可用,并保持清晰标记。
## 评分
四个谨慎的类别是:
- 0–24:**观察到的风险较低**
- 25–49:**建议谨慎**
- 50–74:**观察到的风险升高**
- 75–100:**强烈警告指标**
强烈的当前数据库匹配比本地格式启发式方法具有更高的权重。所有弱
启发式方法合计上限为 24 分,因此它们无法独立产生风险升高或最大风险的结果。错误和不可用的来源总是贡献零分。
在更改任何权重之前,请阅读 [`SCORING.md`](SCORING.md) 和
[`config/scoring-rules.json`](config/scoring-rules.json)。评分更改
需要测试、误报分析、版本升级和文档记录。
## 测试和质量检查
所有自动化测试均使用模拟提供商、本地 fixture、保留的示例域名和测试 DNS
解析器。它们从不访问真实的钓鱼、诈骗、恶意软件或漏洞利用网站。
```
pnpm format:check
pnpm lint
pnpm typecheck
pnpm test:unit
pnpm test:integration
pnpm build
pnpm test:e2e:install
pnpm test:e2e
pnpm audit
```
使用 `pnpm check` 一起运行常见的非浏览器检查。Playwright 会单独
安装浏览器,并有意不隐藏在构建脚本中。
## Docker
```
cp .env.example .env
docker compose build --pull
docker compose up
```
打开 [http://localhost:3000](http://localhost:3000)。最终镜像以非特权用户身份运行,
舍弃 Linux capabilities,在 Compose 中使用只读根文件系统,并包含健康检查。
停止它:
```
docker compose down
```
## 部署
GitHub 应托管源代码仓库,而不是实时的服务器应用程序。实时部署
需要服务器端路由处理和密钥存储,因此 GitHub Pages 不是主要
部署目标。如果稍后添加静态 Pages 构建,它必须是一个清晰标记且没有
钥的演示。
请使用支持服务器的平台或容器主机,并遵循
[`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md)。至少:
1. 审查当前的提供商条款和免费/非商业资格;
2. 仅在平台的密钥管理器中配置已批准的提供商密钥;
3. 设置准确的 HTTPS `APP_BASE_URL`;
4. 对多实例部署使用共享速率限制器;
5. 尽可能使用网络出站控制来隔离出站检查;
6. 配置私密的纠正、隐私和安全联系方式;
7. 测试 SSRF、DNS rebinding、重定向、配额、错误和密钥脱敏;
8. 完成法律文件的律师审查;
9. 启用依赖项更新、CodeQL、密钥扫描和分支保护。
## 隐私设计
- 没有账户、个人资料、广告追踪器、公共评论或公共扫描历史。
- 此版本中没有永久性扫描存储。
- 查询字符串和片段会被尽早丢弃。
- 结果保留在特定标签页范围的浏览器会话存储中,直到被清除或标签页关闭。
- 提供商缓存密钥是单向 hash;在提供商条款允许的情况下,值会在内存中过期。
- 原始 IP 地址不作为速率限制密钥保留。
- 从不提交未知 URL 进行新分析。
- 纠正表单会创建私密邮件草稿,不会由应用程序存储。
请阅读 [`PRIVACY.md`](PRIVACY.md)。运营者必须根据其实际的主机、日志、子处理者、
司法管辖区和保留行为对其进行更新。
## 安全设计
安全控制包括 Zod 输入和提供商 schema、通过 React 进行的输出编码、CSP 和
安全标头、POST 路由上的同源检查、大小和时间限制、结构化日志脱敏、
仅服务器端密钥、每用户应用程序限制、每个提供商的请求计数器和队列、有界
指数退避、手动重定向、DNS 重查、IP 范围拒绝、地址锁定和安全
错误消息。内置的 VirusTotal 队列也会在其记录的每日 500 次请求限制处停止;
来自任何提供商的 HTTP 429/509 响应都会停止进一步的工作,且不对评分产生影响。
请阅读 [`SECURITY.md`](SECURITY.md) 和 [`docs/THREAT_MODEL.md`](docs/THREAT_MODEL.md)。SSRF 防御是
分层的,但无法保证完美保护;仍建议进行生产环境出站隔离。
## 纠正流程
每个结果都链接到 `/corrections`。所有者或授权代表可以请求:
- 进行全新的自动检查;
- 审查可能不准确或已过期的结果;
- 确认之前遭到入侵的站点已修复;
- 删除不必要保留的信息。
该应用程序会生成一个参考编号和一封私密邮件草稿。它不公开争议,也不存储
表单,并且不保证请求会改变评分。请在发布前配置 `CORRECTION_EMAIL`。
切勿将纠正引导至公共 GitHub issue。
## 法律文件
该仓库包含 `DISCLAIMER.md`、`TERMS.md` 和 `PRIVACY.md` 作为谨慎的技术草案。
在公开发布之前,它们需要律师审查,特别是:
- 运营者身份和联系信息;
- 生效日期;
- 适用法律和争议解决;
- 赔偿语言;
- 保修和责任限制;
- 适用于儿童、非营利组织、网络安全服务和隐私的法律;
- 每个提供商的 API/数据条款和所需署名。
任何技术设计、免责声明、开源许可证、条款文档或隐私政策都无法
保证零责任。不要声称该项目是“防诉讼的”。
## GitHub 仓库设置
创建一个空的 GitHub 仓库后:
```
git init
git add .
git commit -m "Initial Website Risk Checker release"
git branch -M main
git remote add origin https://github.com/YOUR-ORG/website-risk-checker.git
git push -u origin main
```
然后:
1. 保护 `main` 分支并要求进行 CI 和 CodeQL 检查;
2. 要求至少一次审查并解决所有对话;
3. 启用私密漏洞报告;
4. 在可用时启用密钥扫描和推送保护;
5. 启用 Dependabot 安全更新;
6. 禁止 Actions 在分叉的 Pull Request 上访问生产环境密钥;
7. 添加仓库主题并替换运营者占位符;
8. 执行[发布前检查清单](docs/PRE_LAUNCH_CHECKLIST.md)。
## 许可证和第三方材料
源代码在 [MIT 许可证](LICENSE) 下提供。MIT 许可证**不会**取代
网站条款、隐私披露、第三方 API 条款、数据许可、负责任的运营、
安全防护措施或律师审查。开源许可不会消除责任。
提供商数据和提供商名称受其自身条款管辖,不会根据 MIT 重新授权。
请参阅 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。
## 路线图
- 独立的安全审查和针对 SSRF 的渗透测试。
- 运营者批准的生产级速率限制后端。
- 在进行单独审查后,提供可选的注重隐私的 Safe Browsing 本地列表模式。
- 审查翻译工作流以确保准确性和可读性。
- 带有明确保留和删除控制的、受审核的私密纠正案例管理。
- 针对提供商条款审查的定期自动化提醒。
公共指控板、用户评分的黑名单、漏洞扫描、未知 URL 提交、
文件分析和公共扫描历史明确不在范围之内。
## 维护者检查清单
- [ ] 重新审查每个提供商的官方条款、配额、定价、署名和隐私行为。
- [ ] 确认非商业资格并确保 `PROJECT_USE_MODE` 如实反映。
- [ ] 禁用任何条款已更改或无法确认的适配器。
- [ ] 替换所有运营者、联系信息、司法管辖区、日期和部署占位符。
- [ ] 完成法律文件的律师审查。
- [ ] 运行格式化、lint、类型检查、单元、集成、构建、E2E、审计和容器检查。
- [ ] 测试私有/保留 IP、DNS rebinding、重定向到内部目标以及 timeout。
- [ ] 配置可信代理行为、共享应用程序限制和提供商配额。
- [ ] 验证密钥永远不会出现在浏览器包、日志、错误、截图或 CI 工件中。
- [ ] 确认纠正请求保持私密,并且保留披露符合实际情况。
- [ ] 启用分支保护、CodeQL、依赖项审查、Dependabot 和密钥扫描。
- [ ] 将完成的审查记录在 `config/provider-compliance.json` 和 `CHANGELOG.md` 中。
标签:TypeScript, URL风险检测, 反取证, 威胁情报, 安全插件, 安全评估, 开发者工具, 特征检测, 自动化攻击