clay-good/qiuth

GitHub: clay-good/qiuth

Qiuth 是一款为 API 密钥添加多因素认证的安全中间件,将 Bearer Token 转化为持有证明令牌,在密钥泄露时仍能阻止未授权访问。

Stars: 5 | Forks: 1

# Qiuth **为 API 密钥提供多因素认证** - 别再把 API 密钥当成普通密码了。 发音为 **chew-auth**。灵感来源于 [Kevin Qiu](https://www.linkedin.com/in/kevinmqiu) ## 问题所在 **API 密钥是单点故障。** 如果你的 API 密钥泄露(被提交到 GitHub、在传输过程中被截获、从日志中失窃),攻击者将获得对你 API 的**无限访问权限**。 ``` # 你的 .env 文件被意外提交到了 GitHub API_KEY=sk_live_abc123def456 # 攻击者发现了它并获得了完全访问权限 curl -H "Authorization: Bearer sk_live_abc123def456" https://api.yourapp.com/data # 成功 - 攻击者下载了你所有的数据 ``` **这种情况比你想象的更为常见:** - 每天都有数以千计的 API 密钥在 GitHub 上泄露 - `.env` 文件被意外提交到公开仓库 - API 密钥被记录在错误消息或监控工具中 - 密钥在传输过程中被截获或从被入侵的系统中失窃 - 即使使用密钥对,如果私钥泄露,一切也就完了 ## 解决方案 **Qiuth 为你的 API 密钥增加了多因素认证**,将它们从 Bearer Token(持有密钥的任何人都可以使用)转变为**持有证明令牌**(你需要密钥加上额外的验证因素)。 ### 多层防御 1. **IP 允许列表** - 第一道防线 - 验证请求是否来自授权位置 - 支持 IPv4/IPv6 CIDR 表示法 - 立即阻止未授权的网络 2. **TOTP MFA** - 基于时间的一次性密码 - 适用于服务账号(程序化运行) - 令牌每 30 秒更改一次 - 即使 API 密钥泄露,攻击者也需要 TOTP 密钥 3. **请求签名** - 加密证明(选择其一): **证书认证**(非对称) - 需要 RSA 私钥对每个请求进行签名 - 服务器上仅存储公钥 - 最适用于外部客户端,或当你需要考虑密钥分发问题时 **HMAC 认证**(对称) - 使用共享密钥进行请求签名 - 设置更简单,对内部服务提供相同的安全性 - 最适用于受信任的环境和服务间通信 4. **时间戳验证** - 防止重放攻击 - 签名请求包含时间戳 - 服务器拒绝过期请求(时间窗口可配置) - 即使请求被截获也无法重放 ### 实际影响 **使用 Qiuth 之后:** ``` # API key 在 GitHub 上泄露 API_KEY=sk_live_abc123def456 # 攻击者尝试使用它 curl -H "X-API-Key: sk_live_abc123def456" https://api.yourapp.com/data # 失败:401 Unauthorized - IP 不在 allowlist 中 # 攻击者需要所有这些条件: # 1. API key(已泄露) # 2. TOTP secret(单独存储) # 3. Signing key(private key 或 HMAC secret) # = 几乎不可能被攻破 ``` ## 为什么选择 Qiuth? ### 非人类身份 (NHI) 的安全盲区 我们在人类账户的多因素认证上投入了大量精力。密码管理器、身份验证器应用、硬件密钥——安全行业已经让 MFA 成为人类用户的标配。 **但是服务账号呢?** 服务账号、API 客户端和机器间通信的集成通常使用以下方式进行身份验证: - 永不轮换的静态 API 密钥 - 没有第二验证因素的 OAuth client_id/client_secret 对 - 没有额外验证的长期有效令牌 这造成了一个根本的安全盲区:**非人类身份的认证强度弱于人类身份**,尽管它们通常拥有对敏感系统更广泛的访问权限。 ### OAuth Client Secret 的问题 许多开发者认为“只需使用 OAuth”就能解决 API 安全问题。但是 OAuth client secret 具有与 API 密钥相同的漏洞: - **Client Secret 是静态的** - 除非手动轮换,否则它们不会改变 - **Client Secret 是可重用的** - 任何拥有该 secret 的人都可以请求令牌 - **Client Secret 可能被截获** - 通过 MITM 中间人攻击截获初始令牌请求,你就能获得 secret - **Client Secret 本质上是密码** - 带有凭证失窃的所有相同风险 JP Morgan Chase 的 CISO [致第三方供应商的公开信](https://www.jpmorganchase.com/about/technology/blog/open-letter-to-our-suppliers) 强调了关于 OAuth 和当前机器间通信认证标准的确切隐患。 ### 为什么 IP 允许列表应当成为标配 一个简单的问题:**为什么 SaaS 应用添加 IP 允许列表如此困难?** 考虑这个真实场景:一名工程师意外将包含根访问密钥的配置文件提交到了公开仓库。几分钟内,自动化扫描器就发现了它。该密钥宣告沦陷。 如果使用一个简单的 IAM 策略,这本来根本不是问题: ``` Deny all access with this key if source IP is not in [VPN_STATIC_IP] ``` 即使是最简单的 IP 验证——在返回响应之前读取 `X-Forwarded-For` 头——也能极大地缩小泄露凭证的波及范围。然而,大多数 API 并不提供这种基本保护。 Qiuth 将 IP 允许列表作为一项核心功能,而不是事后补丁。 ### Qiuth 的方法:为所有身份提供 MFA Qiuth 将我们对人类账户所期望的同等严格的安全标准应用于服务账号: | 人类账户 | 服务账号 (使用 Qiuth) | |--------------|------------------------------| | 密码 | API 密钥 | | 基于 IP 的访问控制 | IP 允许列表 (第 1 层) | | 身份验证器应用 (TOTP) | 面向服务的 TOTP (第 2 层) | | 硬件安全密钥 | 证书签名 (第 3 层) | 结果是:即使你的 API 密钥泄露,攻击者还需要同时攻破你的 TOTP 密钥和你的私钥,并且必须从允许的 IP 地址发起请求。 **这就是针对机器身份的纵深防御。** ## 快速开始 ### 安装 ``` npm install qiuth ``` ### 基本用法 ``` import { QiuthConfigBuilder, QiuthAuthenticator, generateKeyPair } from 'qiuth'; // Generate certificate key pair for maximum security const { publicKey, privateKey } = generateKeyPair({ modulusLength: 2048 }); // Configure all three security layers const config = new QiuthConfigBuilder() .withApiKey('your-api-key') .withIpAllowlist(['192.168.1.0/24']) .withTotp('your-totp-secret') .withCertificate(publicKey) // Add certificate-based authentication .build(); // Authenticate requests const authenticator = new QiuthAuthenticator(); const result = await authenticator.authenticate({ apiKey: 'user-provided-key', clientIp: '192.168.1.100', totpToken: '123456', signature: 'base64-signature', // Required when using withCertificate timestamp: Date.now().toString(), method: 'GET', url: 'https://api.example.com/resource', }, config); if (result.success) { console.log('Authentication successful!'); } else { console.error('Authentication failed:', result.errors); } ``` **注意:** 使用 `.withCertificate(publicKey)` 以获得最高安全性。这要求客户端使用其私钥对每个请求进行加密签名,提供持有证明,即使 API 密钥和 TOTP 密钥泄露也能防止未经授权的访问。 ### 框架中间件 Qiuth 为流行的 Node.js 框架提供了中间件: | 框架 | 函数 | 运行时 | |-----------|----------|---------| | Express | `createQiuthMiddleware` | Node.js | | Fastify | `qiuthFastifyPlugin` | Node.js | | Koa | `createQiuthKoaMiddleware` | Node.js | | Hono | `createQiuthHonoMiddleware` | Node.js, Cloudflare Workers, Deno, Bun | #### Express ``` import express from 'express'; import { createQiuthMiddleware, QiuthConfigBuilder } from 'qiuth'; const app = express(); const qiuthAuth = createQiuthMiddleware({ configLookup: async (apiKey) => { return await db.getApiKeyConfig(apiKey); }, }); app.get('/api/protected', qiuthAuth, (req, res) => { res.json({ message: 'Access granted!' }); }); ``` #### Fastify ``` import fastify from 'fastify'; import { qiuthFastifyPlugin } from 'qiuth'; const app = fastify(); app.register(qiuthFastifyPlugin, { configLookup: async (apiKey) => await db.getApiKeyConfig(apiKey), }); app.get('/protected', { preHandler: app.qiuthAuth }, async (request, reply) => { return { authenticated: true }; }); ``` #### Koa ``` import Koa from 'koa'; import { createQiuthKoaMiddleware } from 'qiuth'; const app = new Koa(); const qiuthMiddleware = createQiuthKoaMiddleware({ configLookup: async (apiKey) => await db.getApiKeyConfig(apiKey), }); app.use(qiuthMiddleware); ``` #### Hono (支持边缘计算) ``` import { Hono } from 'hono'; import { createQiuthHonoMiddleware } from 'qiuth'; const app = new Hono(); app.use('/api/*', createQiuthHonoMiddleware({ configLookup: async (apiKey) => await db.getApiKeyConfig(apiKey), })); ``` [完整的中间件文档](./docs/middleware-integrations.md) ## 交互式演示 **5 分钟即可体验 Qiuth 的实际运行!** ``` # Clone 仓库 git clone https://github.com/clay-good/qiuth.git cd qiuth # Install dependencies npm install # 启动 interactive demo npm run demo ``` 演示服务器将启动并显示测试凭证。打开一个新的终端并尝试测试命令,看看所有三个安全层的实际运作! **你将体验到:** - 级别 1:基本 API 密钥认证 - 级别 2:API 密钥 + IP 允许列表 - 级别 3:API 密钥 + IP + TOTP MFA - 级别 4:最高安全级别(所有三层) - 失败场景(凭证错误、令牌过期、签名无效) [**完整演示指南**](./demo/README.md) ## 功能 ### 安全性 - **三层认证** - 基于 IP、TOTP 和证书 - **快速失败验证** - 在第一次失败时即停止,以保证性能 - **防止重放攻击** - 时间戳验证 - **安全的凭证生成** - 加密安全的随机生成 - **API 密钥哈希** - 使用 SHA-256 进行安全存储 ### 开发者体验 - **TypeScript 优先** - 包含完整的类型定义 - **流式 API** - 直观的配置构建器 - **Express 中间件** - 即插即用的认证 - **HTTP 客户端** - 自动请求签名 - **CLI 工具** - 轻松生成凭证 ### 生产就绪 - **零停机凭证轮换** - 为更新提供过渡期 - **结构化日志** - 全面的可观测性 - **指标收集** - 跟踪认证性能 - **环境配置** - 从环境变量加载 - **全面的错误处理** - 详细的错误信息 ### 构建与分发 - **双模块支持** - ESM 和 CommonJS - **可摇树优化** - 按需导入 - **零依赖** - 仅使用 Node.js 内置模块 - **经过充分测试** - 318 个测试,90%+ 覆盖率 ## 使用场景 ### 1. 服务间认证 使用 MFA 保护微服务通信: ``` const config = new QiuthConfigBuilder() .withApiKey(process.env.API_KEY) .withIpAllowlist(['10.0.0.0/8']) // Internal network .withTotp(process.env.TOTP_SECRET) .build(); ``` ### 2. API 密钥管理 为你现有的 API 密钥系统添加 MFA: ``` app.use('/api', createQiuthMiddleware({ config })); ``` ### 3. 合规性要求 满足 PCI DSS、SOC 2、HIPAA 安全要求: ``` const config = new QiuthConfigBuilder() .withApiKey(apiKey) .withIpAllowlist(allowedIps) .withTotp(totpSecret) .withCertificate(publicKey) // Maximum security .build(); ``` ### 4. CI/CD 流水线安全 保护自动化部署安全: ``` // GitHub Actions, Jenkins, etc. const client = new QiuthClient({ apiKey: process.env.API_KEY, totpSecret: process.env.TOTP_SECRET, privateKey: process.env.PRIVATE_KEY, }); ``` ## 安全性 Qiuth 的设计以安全性为首要任务: - **不记录敏感数据** - API 密钥和 secret 绝不会被记录 - **加密安全** - 使用 Node.js crypto 模块 - **兼容 RFC 标准** - TOTP 遵循 RFC 6238 标准 - **行业标准** - RSA-SHA256 签名 - **定期审计** - 自动化的安全扫描 ## 性能 Qiuth 专为生产环境使用而设计,开销极低: - **IP 验证**:< 1ms - **TOTP 验证**:< 5ms - **证书验证**:< 10ms - **总计**:所有三层 < 20ms **包体积:** - ESM:~60 KB - CommonJS:~61 KB - TypeScript 声明文件:~48 KB
**别再把 API 密钥当成普通密码了。今天就加入多因素认证吧。** [开始使用](./docs/getting-started.md) • [尝试演示](./demo/README.md) • [自述文件](https://github.com/clay-good/qiuth/readme.md)
标签:API安全, JSONLines, JSON输出, MFA, MITM代理, 网络访问控制, 自动化攻击, 零信任