Flask AppBuilder 中已长期弃用的 OpenID 认证方法的漏洞
最近,Islam Rzayev 让我们注意到 Flask AppBuilder 中长期已弃用的 OpenID 认证方式存在漏洞。该漏洞允许恶意用户通过伪造特制请求并实现自己的 OpenID 服务,进而冒充任意 Airflow UI 用户的身份。虽然这是一种已废弃且几乎不再使用的认证方式,但我们仍然严肃对待此问题。
此问题仅影响在其 webserver_config.py 文件中将 AUTH_OID 设置为 AUTH_TYPE 的用户。这是一种非常古老且已弃用的认证方式,几乎不会被任何人使用。
我们建议即便是仍在使用此认证方式的少数用户也应立即采取行动,要么升级到 Apache Airflow 2.8.2,要么切换到其他认证方式(如果他们无法立即完成上述任一操作,可使用我们提供的解决方案)。
需要强调的是,许多用户可能会因为名称混淆而误解:OpenID 并不等同于 OpenID Connect。这两者是完全不同的协议,OpenID Connect(亦称 OIDC)是现代且广泛使用的协议,而 OpenID 是一种已在十多年前被废弃的遗留协议,自此几乎被社区所有成员放弃,包括 Flask AppBuilder 示例服务中支持它的所有服务,因此几乎不可能还有人在使用它。
由于这种极不可能的配置,Flask AppBuilder CVE 的评级仅为“中等”,而非“严重”。受影响的用户数量极少(甚至可能没有),且不太可能成为攻击目标。然而,我们仍建议仍在使用 AUTH_OID 的用户进行修复。
此漏洞已在 Flask AppBuilder 4.3.11 中修复,Apache Airflow 2.8.2 使用了该版本的 Flask Application Builder。我们建议仍在使用此认证方式的用户要么切换到其他认证方式,要么升级到 Apache Airflow 2.8.2。如果他们无法快速完成上述任一方案,应使用下面提供的解决办法。
影响
当 Flask-AppBuilder 的 AUTH_TYPE 设置为 AUTH_OID 时,攻击者可以伪造 HTTP 请求,诱使后端使用任意指定的 OpenID 服务。如果攻击者部署并使其自定义的 OpenID 服务对后端可访问,漏洞可能让攻击者获得未经授权的特权访问。
该漏洞仅在应用使用 OpenID(而非 OpenID Connect,也称 OIDC)时才可被利用。目前,该协议已被视为遗留协议,使用率大幅下降。
可能的修复方案
- 更改您的认证方式——如果您正在使用
AUTH_OID,几乎没有商业服务支持它,它在十年前已被弃用,并在四年前被社区几乎所有人抛弃。最佳做法是选择其他认证方式。 - 升级到 Apache Airflow 2.8.2(该版本同时升级到包含修复的 Flask-AppBuilder 4.3.11)
- 如果无法升级,请使用以下解决办法
解决办法
如果无法升级或更改认证方式,请在您的 webserver_config.py 文件中添加以下内容以修复此问题
import os
from flask import flash, redirect
from flask_appbuilder.security.forms import LoginForm_oid
from flask_appbuilder.security.views import AuthOIDView
from flask_appbuilder.views import expose
from airflow.www.security import AirflowSecurityManager
basedir = os.path.abspath(os.path.dirname(__file__))
class FixedOIDView(AuthOIDView):
@expose("/login/", methods=["GET", "POST"])
def login(self, flag=True):
form = LoginForm_oid()
if form.validate_on_submit():
identity_url = None
for provider in self.appbuilder.sm.openid_providers:
if provider.get("url") == form.openid.data:
identity_url = form.openid.data
if identity_url is None:
flash(self.invalid_login_message, "warning")
return redirect(self.appbuilder.get_url_for_login)
return super().login(flag=flag)
class FixedAirflowSecurityManager(AirflowSecurityManager):
authoidview = FixedOIDView
SECURITY_MANAGER_CLASS = FixedAirflowSecurityManager
致谢
衷心感谢 Islam Rzayev 负责任地发现并报告此问题,感谢 Daniel Gaspar 在此事上密切合作,并与使用 Flask AppBuilder 的 Apache Superset 一同协调披露。
分享