Apache Superset SQL注入绕过技术分析
1. 漏洞背景
Apache Superset是一个开源的数据探索和可视化平台,允许用户通过Web界面创建图表和仪表板,无需编写复杂SQL查询。在版本4.0.1中,存在一个安全机制绕过漏洞,允许攻击者执行任意SQL查询,绕过平台的安全限制。
2. 漏洞发现过程
2.1 初始发现
在安全审计过程中,发现可以通过以下API路径与Superset交互:
/superset/explore_json//api/v1/chart/data
2.2 安全机制分析
Superset正常允许执行SQL查询,但实施了安全机制阻止任意SQL请求的执行。通过代码审计发现关键限制逻辑。
3. 代码分析
3.1 关键函数:validate_adhoc_subquery()
位于superset/models/helpers.py,主要功能是检查SQL是否包含子查询或嵌套子查询。
def validate_adhoc_subquery(
sql: str,
database_id: int,
default_schema: str,
) -> str:
"""
检查adhoc SQL是否包含子查询或带有表的嵌套子查询
"""
statements = []
for statement in sqlparse.parse(sql):
if has_table_query(statement):
if not is_feature_enabled("ALLOW_ADHOC_SUBQUERY"):
raise SupersetSecurityException(
SupersetError(
error_type=SupersetErrorType.ADHOC_SUBQUERY_NOT_ALLOWED_ERROR,
message=_("Custom SQL fields cannot contain sub-queries."),
level=ErrorLevel.ERROR,
)
)
statement = insert_rls_in_predicate(statement, database_id, default_schema)
statements.append(statement)
return ";\n".join(str(statement) for statement in statements)
3.2 子查询检测函数:has_table_query()
位于superset/sql_parse.py,使用sqlparse库解析SQL查询:
def has_table_query(token_list: TokenList) -> bool:
"""
检查语句是否有从表读取的查询
"""
state = InsertRLSState.SCANNING
for token in token_list.tokens:
# 忽略注释
if isinstance(token, sqlparse.sql.Comment):
continue
# 递归检查子token列表
if isinstance(token, TokenList) and has_table_query(token):
return True
# 发现源关键字(FROM/JOIN)
if imt(token, m=[(Keyword, "FROM"), (Keyword, "JOIN")]):
state = InsertRLSState.SEEN_SOURCE
# 在FROM/JOIN后发现标识符/关键字
elif state == InsertRLSState.SEEN_SOURCE and (
isinstance(token, sqlparse.sql.Identifier) or token.ttype == Keyword
):
return True
# 未发现任何内容,离开源
elif state == InsertRLSState.SEEN_SOURCE and token.ttype != Whitespace:
state = InsertRLSState.SCANNING
return False
4. 漏洞利用技术
4.1 PostgreSQL XML函数绕过
通过研究发现PostgreSQL提供以下XML相关函数可以绕过安全检测:
-
query_to_xml(query text, nulls boolean, tableforest boolean, targetns text)- 将关系表内容映射为XML值
-
query_to_xml_and_xmlschema(query text, nulls boolean, tableforest boolean, targetns text)- 生成XML数据映射及其对应的XML Schema
-
table_to_xml(tbl regclass, nulls boolean, tableforest boolean, targetns text)- 将指定表内容映射为XML值
-
table_to_xml_and_xmlschema(tbl regclass, nulls boolean, tableforest boolean, targetns text)- 生成表内容的XML映射和Schema
-
database_to_xml(nulls boolean, tableforest boolean, targetns text)- 生成整个数据库的XML映射
4.2 绕过原理
这些函数接受字符串参数作为SQL查询执行,但在解析过程中:
- 恶意查询被视为字符串(函数参数)
- 被"标记化"为字符串而非SQL语句
has_table_query函数无法检测到注入
5. 漏洞复现步骤
- 搭建测试环境:
git clone https://github.com/apache/superset
cd superset
docker compose -f docker-compose-image-tag.yml up
-
构造恶意请求,使用PostgreSQL XML函数包装SQL查询
-
通过API端点发送请求:
/superset/explore_json//api/v1/chart/data
6. 防御建议
-
升级到最新版本Apache Superset
-
加强输入验证:
- 对XML函数调用进行限制
- 扩展SQL解析逻辑
-
实施最小权限原则:
- 数据库用户只授予必要权限
- 限制敏感表的访问
-
启用审计日志:
- 记录所有SQL查询
- 监控异常查询模式
7. 总结
该漏洞展示了即使成熟的数据平台也可能存在安全机制绕过风险。通过:
- 深入代码审计发现安全限制逻辑
- 研究数据库文档找到特殊函数
- 利用函数参数特性绕过标记化检测
强调了持续安全审计和及时漏洞修复的重要性。