curl 深度教程 / 第 06 章:认证机制
第 06 章:认证机制
认证(Authentication)是 API 安全的第一道防线。curl 支持几乎所有主流的 HTTP 认证方案,从简单的 Basic Auth 到复杂的 OAuth2 流程。
6.1 认证方案概览
| 认证方案 | 安全性 | 复杂度 | curl 选项 | 适用场景 |
|---|---|---|---|---|
| Basic | 低(Base64 编码) | ★☆☆☆☆ | -u user:pass | 内部服务、开发环境 |
| Bearer Token | 中 | ★★☆☆☆ | -H "Authorization: Bearer ..." | JWT/OAuth2 |
| Digest | 中 | ★★☆☆☆ | --digest -u user:pass | 旧系统兼容 |
| API Key | 中 | ★☆☆☆☆ | -H "X-API-Key: ..." | 公开 API |
| OAuth2 | 高 | ★★★★☆ | 多步骤流程 | 第三方授权 |
| 客户端证书 (mTLS) | 高 | ★★★☆☆ | --cert / --key | 企业级安全 |
| NTLM | 中高 | ★★★☆☆ | --ntlm -u user:pass | Windows 域环境 |
| Kerberos (SPNEGO) | 高 | ★★★★☆ | --negotiate -u : | 企业 SSO |
| AWS Signature | 高 | ★★★☆☆ | 自定义头部签名 | AWS API |
| Hawk | 中高 | ★★★☆☆ | 自定义头部签名 | Web API |
6.2 Basic Authentication
Basic Auth 是最简单的认证方式,将 username:password 进行 Base64 编码后放入 Authorization 头。
基本用法
# 使用 -u 选项(推荐)
curl -u admin:secret123 https://api.example.com/admin
# 等价于手动设置 Authorization 头
# Base64("admin:secret123") = "YWRtaW46c2VjcmV0MTIz"
curl -H "Authorization: Basic YWRtaW46c2VjcmV0MTIz" \
https://api.example.com/admin
# 仅指定用户名(curl 会交互式提示输入密码)
curl -u admin https://api.example.com/admin
# 密码中包含特殊字符
curl -u 'admin:p@ss:word/123' https://api.example.com/admin
# 或使用转义
curl -u admin:p@ss\:word/123 https://api.example.com/admin
# 使用 .netrc 文件(避免命令行暴露密码)
curl --netrc https://api.example.com/admin
.netrc 文件
# ~/.netrc 文件格式
# machine <主机名> login <用户名> password <密码>
machine api.example.com
login admin
password secret123
machine ftp.example.com
login ftpuser
password ftppass
# 使用 .netrc
curl --netrc https://api.example.com/admin
# 指定 .netrc 文件路径
curl --netrc-file /path/to/.netrc https://api.example.com/admin
# 权限设置(重要!)
chmod 600 ~/.netrc
⚠️ 安全警告:Basic Auth 仅是 Base64 编码,不是加密!必须配合 HTTPS 使用。
6.3 Bearer Token
Bearer Token 是当前最流行的 API 认证方式,广泛用于 JWT(JSON Web Token)和 OAuth2。
基本用法
# 使用 -H 设置 Bearer Token
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -H "Authorization: Bearer $TOKEN" \
https://api.example.com/protected
# 获取 Token 后访问 API
# 1. 获取 Token
TOKEN=$(curl -s -X POST https://auth.example.com/token \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "secret"}' \
| jq -r '.access_token')
# 2. 使用 Token 访问 API
curl -H "Authorization: Bearer $TOKEN" \
https://api.example.com/users
# 检查 Token 是否有效
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
https://api.example.com/verify
# 200 → 有效, 401 → 过期/无效
JWT Token 解码
# 解码 JWT Token(查看 Payload)
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .
# 检查 Token 过期时间
EXPIRY=$(echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq -r '.exp')
NOW=$(date +%s)
if [ "$EXPIRY" -lt "$NOW" ]; then
echo "Token 已过期"
fi
6.4 Digest Authentication
Digest Auth 比 Basic Auth 更安全,它使用挑战-响应机制,密码不直接传输。
基本用法
# 使用摘要认证
curl --digest -u admin:secret123 https://api.example.com/admin
# curl 会自动处理挑战-响应流程:
# 1. 服务器返回 401 和 WWW-Authenticate: Digest 头
# 2. curl 计算摘要并重新发送请求
# 3. 服务器验证摘要并返回资源
# 强制使用 Digest(不允许回退到 Basic)
curl --digest --anyauth -u admin:secret123 https://api.example.com/admin
Digest 认证流程
客户端 服务器
| |
|--- GET /admin ---------------->|
| |
|<-- 401 Unauthorized ----------|
| WWW-Authenticate: Digest |
| realm="example", |
| nonce="abc123" |
| |
|--- GET /admin ---------------->|
| Authorization: Digest |
| username="admin", |
| response="哈希值" |
| |
|<-- 200 OK --------------------|
6.5 OAuth2 流程
OAuth2 是第三方应用获取用户授权的标准协议。curl 可以手动实现各种 OAuth2 流程。
Authorization Code Flow(授权码流程)
# 1. 用户在浏览器中授权
# 打开以下 URL:
echo "请在浏览器中访问:"
echo "https://auth.example.com/authorize?\
client_id=YOUR_CLIENT_ID&\
redirect_uri=https://callback.example.com&\
response_type=code&\
scope=read+write"
# 2. 用户授权后,从回调 URL 获取授权码
AUTH_CODE="abc123code" # 从回调 URL 的 code 参数获取
# 3. 用授权码换取 Access Token
TOKEN_RESPONSE=$(curl -s -X POST https://auth.example.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=$AUTH_CODE" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "redirect_uri=https://callback.example.com")
# 4. 提取 Access Token
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
REFRESH_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.refresh_token')
# 5. 使用 Access Token 访问 API
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
https://api.example.com/userinfo
Client Credentials Flow(客户端凭证流程)
# 适用于服务间通信(无用户参与)
TOKEN_RESPONSE=$(curl -s -X POST https://auth.example.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=SERVICE_CLIENT_ID" \
-d "client_secret=SERVICE_CLIENT_SECRET" \
-d "scope=api.read")
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
Refresh Token Flow
# 使用 Refresh Token 获取新的 Access Token
NEW_TOKEN=$(curl -s -X POST https://auth.example.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=$REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET")
ACCESS_TOKEN=$(echo "$NEW_TOKEN" | jq -r '.access_token')
REFRESH_TOKEN=$(echo "$NEW_TOKEN" | jq -r '.refresh_token')
Password Grant(密码模式,已废弃但仍常见)
# 仅适用于高度信任的第一方应用
TOKEN_RESPONSE=$(curl -s -X POST https://auth.example.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "[email protected]" \
-d "password=userpassword" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=read+write")
6.6 客户端证书认证(mTLS)
客户端证书(Mutual TLS, mTLS)要求客户端也提供证书,实现双向认证。
基本用法
# 使用客户端证书和私钥
curl --cert client.crt --key client.key \
https://api.example.com/secure
# 使用 PEM 格式证书(证书和私钥在同一个文件)
curl --cert client.pem https://api.example.com/secure
# 带密码保护的私钥
curl --cert client.crt --key client.key \
--pass "私钥密码" \
https://api.example.com/secure
# 使用 PKCS#12 格式证书
curl --cert client.p12 --cert-type P12 \
https://api.example.com/secure
# 指定 TLS 版本
curl --tlsv1.3 --cert client.crt --key client.key \
https://api.example.com/secure
证书格式转换
# PKCS#12 转 PEM
openssl pkcs12 -in client.p12 -out client.pem -nodes
# PEM 转 PKCS#12
openssl pkcs12 -export -in client.crt -inkey client.key \
-out client.p12
# 查看证书信息
openssl x509 -in client.crt -text -noout
# 验证证书链
openssl verify -CAfile ca.crt client.crt
6.7 NTLM 认证
NTLM(NT LAN Manager)是 Windows 域环境中的认证协议。
# NTLM 认证
curl --ntlm -u 'DOMAIN\username:password' \
https://intranet.example.com/api
# 使用 UPN 格式
curl --ntlm -u '[email protected]:password' \
https://intranet.example.com/api
# NTLMv2(默认使用最新版本)
curl --ntlm -u 'CORP\zhangsan:password123' \
https://fileserver.corp.local/documents/report.xlsx
# 仅用户名(交互式输入密码)
curl --ntlm -u 'CORP\zhangsan' \
https://fileserver.corp.local/api
6.8 Kerberos / SPNEGO 认证
Kerberos 是企业级单点登录(SSO)的标准协议。
# 前提:已通过 kinit 获取 Kerberos 票据
kinit [email protected]
# Negotiate(SPNEGO)认证
curl --negotiate -u : https://api.corp.example.com/data
# 使用 keytab 文件
export KRB5CCNAME=/tmp/krb5cc_user
kinit -k -t /etc/krb5.keytab service/[email protected]
curl --negotiate -u : https://api.corp.example.com/data
# 强制使用 SPNEGO
curl --negotiate -u : --auth-no-challenge \
https://api.corp.example.com/data
6.9 API Key 认证
API Key 不是 HTTP 标准认证方案,但被广泛使用。
常见传递方式
# 方式 1:通过自定义头部(最常见)
curl -H "X-API-Key: your-api-key-here" \
https://api.example.com/data
# 方式 2:通过 Authorization 头
curl -H "Authorization: ApiKey your-api-key-here" \
https://api.example.com/data
# 方式 3:通过查询参数(不推荐,会出现在日志中)
curl "https://api.example.com/data?api_key=your-api-key-here"
# 方式 4:通过 Cookie
curl -b "api_key=your-api-key-here" \
https://api.example.com/data
# 从环境变量读取 API Key
curl -H "X-API-Key: $MY_API_KEY" https://api.example.com/data
常见 API 平台的认证方式
| 平台 | 认证方式 | curl 示例 |
|---|---|---|
| GitHub | Bearer Token | -H "Authorization: Bearer ghp_..." |
| GitLab | Private Token | -H "PRIVATE-TOKEN: glpat-..." |
| Stripe | Basic Auth | -u sk_test_...: |
| OpenAI | Bearer Token | -H "Authorization: Bearer sk-..." |
| AWS | Signature V4 | 自定义签名头部 |
| Google Cloud | Bearer Token | -H "Authorization: Bearer ya29..." |
| Azure | Bearer Token | -H "Authorization: Bearer eyJ..." |
| Cloudflare | API Token | -H "Authorization: Bearer ..." |
6.10 认证方案自动协商
# 使用 --anyauth 让 curl 自动选择最佳认证方案
curl --anyauth -u admin:secret https://api.example.com/admin
# 使用 --anyauth 与 -w 检查实际使用的方案
curl --anyauth -u admin:secret -v https://api.example.com/admin 2>&1 \
| grep "Authorization:"
# 强制使用特定方案(不协商)
curl --basic -u admin:secret https://api.example.com/admin
curl --digest -u admin:secret https://api.example.com/admin
curl --ntlm -u admin:secret https://api.example.com/admin
curl --negotiate -u : https://api.example.com/admin
注意事项
- 永远使用 HTTPS:Basic Auth 的密码只是 Base64 编码,明文传输等于裸奔
- Token 过期处理:脚本中应检测 401 响应并自动刷新 Token
- 不要在命令行中硬编码密码:使用环境变量、.netrc 或密码管理器
- 客户端证书安全:私钥文件权限应设为
600,只有属主可读 - API Key 轮换:定期更换 API Key,使用环境变量存储
# 安全地从命令历史中隐藏密码
read -sp "Enter password: " PASS
curl -u "admin:$PASS" https://api.example.com/secure
unset PASS
# 或使用配置文件
curl --config curl.conf https://api.example.com/secure
# curl.conf 内容:--user admin:secret
扩展阅读
- HTTP Authentication (MDN)
- OAuth 2.0 规范 (RFC 6749)
- JWT (RFC 7519)
- HTTP Basic Auth (RFC 7617)
- HTTP Digest Auth (RFC 7616)
- curl 认证选项文档
📖 下一章:第 07 章:POST 数据与上传 — 深入了解表单提交、JSON 上传、文件上传和 multipart 编码。