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 是一种遗留协议,它在 10 多年前就被弃用,此后几乎被社区中的所有人放弃,包括 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,则几乎没有商业服务支持它,它在 10 年前被弃用,并且在 4 年前几乎被社区中的所有人放弃。您最好的选择是选择不同的身份验证方法。
  • 升级到 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 协调披露。

分享

另请阅读

Airflow Summit 2022

Jarek Potiuk

Airflow Summit 2022 来了

开发 Apache Airflow 就像“微风”一样

Jarek Potiuk

一位首席软件工程师的开发效率之旅。了解 Jarek 和他的团队如何为社区加速和简化 Airflow 开发。