HTTP 认证基础:Basic Auth 与 Digest Auth
HTTP 认证是 API 安全的第一道防线。在 OpenAPI 规范中,securitySchemes 字段最常引用的两种 HTTP 认证方案就是 Basic Auth 和 Digest Auth。理解它们的原理、实现方式和适用场景,是掌握 OpenAPI 权限验证的基石。
2.1 HTTP Basic Auth 原理与实现
2.1.1 工作原理
Basic Auth 是最简单的 HTTP 认证方式。客户端在请求头中直接发送 用户名:密码 的 Base64 编码值。服务器解码后验证凭据。
- 认证头格式:
Authorization: Basic <Base64(user:password)> - 无状态:每次请求都携带凭据,服务器无需维护会话。
- 明文传输:Base64 是编码而非加密,中间人可轻易解码。
关键点:Basic Auth 必须配合 HTTPS 使用,否则密码等于明文传输。
2.1.2 OpenAPI 规范定义
components:
securitySchemes:
basicAuth:
type: http
scheme: basic
description: "使用用户名和密码进行 Basic 认证"
security:
- basicAuth: []
2.1.3 服务端实现示例(Node.js + Express)
const express = require('express');
const app = express();
app.use((req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Basic ')) {
res.set('WWW-Authenticate', 'Basic realm="API Access"');
return res.status(401).send('Unauthorized');
}
const base64Credentials = authHeader.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');
// 验证凭据(示例硬编码,生产应查数据库)
if (username === 'admin' && password === 'secret123') {
req.user = { username };
next();
} else {
res.status(401).send('Invalid credentials');
}
});
app.get('/api/protected', (req, res) => {
res.json({ message: `Hello ${req.user.username}` });
});
app.listen(3000);
2.2 HTTP Digest Auth 原理与实现
2.2.1 工作原理
Digest Auth 解决了 Basic Auth 的密码明文问题。它使用 挑战-响应 机制,服务器发送随机数(nonce),客户端用密码和 nonce 计算哈希值,服务器验证哈希而非密码本身。
- 认证流程:服务器返回 401 +
WWW-Authenticate头 → 客户端计算响应 → 服务器验证。 - 哈希算法:默认使用 MD5,计算
HA1:nonce:HA2。 - 防重放:nonce 每次不同,防止重放攻击。
提示:Digest Auth 虽然比 Basic Auth 安全,但仍易受中间人攻击(MITM),且 MD5 已不再安全。现代 API 更推荐 Bearer Token 或 OAuth 2.0。
2.2.2 OpenAPI 规范定义
components:
securitySchemes:
digestAuth:
type: http
scheme: digest
description: "使用 Digest 挑战-响应认证"
security:
- digestAuth: []
2.2.3 服务端实现示例(Node.js + Express)
const express = require('express');
const crypto = require('crypto');
const app = express();
const users = { 'admin': 'secret123' };
let nonceStore = {};
app.get('/api/protected', (req, res) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Digest ')) {
const nonce = crypto.randomBytes(16).toString('hex');
nonceStore[nonce] = Date.now();
res.set('WWW-Authenticate', `Digest realm="API", nonce="${nonce}", qop="auth"`);
return res.status(401).send('Unauthorized');
}
// 解析 Digest 参数
const params = {};
authHeader.replace(/Digest\s+/,'').split(', ').forEach(p => {
const [k, v] = p.split('=');
params[k] = v.replace(/"/g, '');
});
const { username, realm, nonce, uri, response, qop, nc, cnonce } = params;
const password = users[username];
if (!password) return res.status(401).send('Invalid user');
// 计算期望的响应
const HA1 = crypto.createHash('md5').update(`${username}:${realm}:${password}`).digest('hex');
const HA2 = crypto.createHash('md5').update(`GET:${uri}`).digest('hex');
const expectedResponse = crypto.createHash('md5')
.update(`${HA1}:${nonce}:${nc}:${cnonce}:${qop}:${HA2}`)
.digest('hex');
if (response === expectedResponse) {
res.json({ message: `Hello ${username}` });
} else {
res.status(401).send('Invalid credentials');
}
});
app.listen(3000);
2.3 核心流程对比
下图展示了 Basic Auth 与 Digest Auth 的认证流程差异:
2.4 优缺点分析
| 特性 | Basic Auth | Digest Auth |
|---|---|---|
| 实现复杂度 | 极低,仅需 Base64 编解码 | 较高,需处理 nonce、qop、哈希计算 |
| 密码传输 | Base64 编码(可逆) | MD5 哈希(不可逆) |
| HTTPS 必要性 | 必须,否则密码完全暴露 | 推荐,虽不传明文但易受 MITM 攻击 |
| 重放攻击防护 | 无 | 有(通过 nonce + nc 计数器) |
| 服务端存储 | 需存储明文或可逆密码 | 可存储 HA1 哈希值 |
| 性能 | 高,无额外计算 | 中,每次请求需哈希计算 |
| 浏览器支持 | 所有浏览器原生支持 | 所有浏览器原生支持 |
| 现代 API 适用性 | 仅适合内部工具或测试 | 较少使用,已被 Bearer Token 取代 |
2.5 安全建议与最佳实践
警告:Basic Auth 和 Digest Auth 在现代 API 安全中已属于过时方案。除非是遗留系统或极低安全要求的内部工具,否则应优先考虑 Bearer Token、OAuth 2.0 或 API Key。
- Basic Auth 使用场景:快速原型、内部调试工具、与旧系统兼容。
- Digest Auth 使用场景:无法使用 HTTPS 的遗留环境(极少见)。
- OpenAPI 规范建议:在
securitySchemes中明确标注认证类型,并在描述中说明安全要求。 - 密码存储:服务端应使用 bcrypt 等强哈希算法存储密码,而非明文或 MD5。
- 速率限制:对认证端点实施速率限制,防止暴力破解。
2.6 OpenAPI 中的组合使用
在 OpenAPI 3.x 中,可以同时定义多种 HTTP 认证方案,并在不同路径上应用不同的安全策略:
components:
securitySchemes:
basicAuth:
type: http
scheme: basic
digestAuth:
type: http
scheme: digest
paths:
/api/legacy:
get:
security:
- basicAuth: []
responses:
'200':
description: Legacy API 响应
/api/secure:
get:
security:
- digestAuth: []
responses:
'200':
description: Secure API 响应
实践要点:在 OpenAPI 文档中,
security 字段可以定义多个认证方案(OR 关系),也可以在一个方案中定义多个作用域(AND 关系)。对于 HTTP Basic/Digest,通常只使用单个方案。