You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何保护Superset自定义免登场景下的/login/端点安全性?

Superset自定义免登接口的安全加固方案

方案1:共享密钥签名校验(最高优先级实现)

这是成本最低、安全性足够的方案,操作逻辑如下:

  • 自有Web应用和Superset提前约定好唯一的共享密钥,保存在两边的服务配置中,绝不对外暴露
  • 自有应用生成跳转Superset的链接时,额外传递3个参数:timestamp(当前10位/13位时间戳)、nonce(随机字符串,防重放)、sign(签名值)
    • 签名算法参考:sign = HMAC-SHA256(共享密钥, username + "|" + role + "|" + timestamp + "|" + nonce)
  • Superset的login逻辑中,先做三层校验,全部通过再执行自动登录逻辑:
    1. 校验timestamp是否在当前时间前后5分钟范围内,过期直接拒绝
    2. 用相同的算法和参数重新计算签名,和请求传递的sign对比,不一致直接拒绝
    3. 可选:把用过的nonce存入缓存,设置10分钟过期,同一个nonce只能用一次,防止链接被盗用重放
  • 额外注意:角色信息不要直接从URL参数取,要么包含在签名校验范围内,要么Superset直接对接自有系统的用户角色接口查询,避免用户篡改URL提升权限

对应的代码修改示例:

import hmac
import hashlib
import time
from flask import request, redirect
from flask_login import login_user
from superset.security import SupersetSecurityManager
from flask_appbuilder.security.views import AuthDBView
from flask_appbuilder import expose

# 共享密钥,建议从环境变量读取,不要硬编码
SHARED_SECRET = b"your_custom_shared_secret_here"
# 签名有效期,单位秒
VALID_DURATION = 300

class CustomAuthDBView(AuthDBView):

    @expose('/login/', methods=['GET', 'POST'])
    def login(self):
        redirect_url = self.appbuilder.get_url_for_index
        user_name = request.args.get('username')
        user_role = request.args.get('role')
        timestamp = request.args.get('timestamp')
        sign = request.args.get('sign')
        nonce = request.args.get('nonce')

        # 开启自动登录逻辑前先做安全校验
        if user_name is not None:
            # 校验所有必填参数是否存在
            if not all([user_role, timestamp, sign, nonce]):
                return super(CustomAuthDBView,self).login()
            # 校验时间是否有效
            try:
                ts = int(timestamp)
                if abs(time.time() - ts) > VALID_DURATION:
                    print('链接已过期', 'warning')
                    return super(CustomAuthDBView,self).login()
            except ValueError:
                return super(CustomAuthDBView,self).login()
            # 校验签名
            raw_str = f"{user_name}|{user_role}|{timestamp}|{nonce}".encode()
            computed_sign = hmac.new(SHARED_SECRET, raw_str, hashlib.sha256).hexdigest()
            if not hmac.compare_digest(computed_sign, sign):
                print('签名校验失败', 'warning')
                return super(CustomAuthDBView,self).login()
            # 校验通过后再执行原有登录、创建用户逻辑
            user = self.appbuilder.sm.find_user(username=user_name)
            if not user:
                role = self.appbuilder.sm.find_role(user_role)
                if not role:
                    return super(CustomAuthDBView,self).login()
                user = self.appbuilder.sm.add_user(user_name, user_name, 'last_name', user_name + "@domain.com", role, password = "random_generated_password_not_fixed")
            if user:
                login_user(user, remember=False)
                return redirect(redirect_url)

        else:
            print('Unable to auto login', 'warning')
            return super(CustomAuthDBView,self).login()

class CustomSecurityManager(SupersetSecurityManager):
    authdbview = CustomAuthDBView
    def __init__(self, appbuilder):
        super(CustomSecurityManager, self).__init__(appbuilder)

方案2:辅助加固措施

  • 校验请求的Referer头,只允许来自自有应用域名的请求进入自动登录逻辑,不过Referer可伪造,只能作为辅助手段,不能作为唯一校验
  • 原有逻辑中创建用户的固定密码要改成随机生成的强密码,避免有人用固定密码走常规登录入口登录
  • 不要开启GET请求的用户创建逻辑,如果用户不存在,建议先跳转自有系统做校验后再同步创建,避免被遍历用户名批量创建账号
  • 生产环境不要在URL中传递敏感参数,可以改用JWT令牌把所有用户信息加密后作为单个参数传递,Superset侧只需要校验JWT的签名和有效期即可,不用处理多个参数的签名逻辑

内容的提问来源于stack exchange,提问作者Swastik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 05:06:03