This is an automated email from the ASF dual-hosted git repository.

casionone pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/linkis.git


The following commit(s) were added to refs/heads/master by this push:
     new 1da0c6790c #AI COMMIT# [SECURITY][DS] Block JDBC URL-option injection 
via instance/database field (#5450)
1da0c6790c is described below

commit 1da0c6790c4784c2e3f467ba1ac4cfdd5035af50
Author: aiceflower <[email protected]>
AuthorDate: Fri Jun 26 16:59:52 2026 +0800

    #AI COMMIT# [SECURITY][DS] Block JDBC URL-option injection via 
instance/database field (#5450)
    
    The DB2 SqlConnection classes interpolate the user-supplied instance
    value directly into the JDBC URL via String.format("jdbc:db2://%s:%s/%s", 
...).
    A value containing URL option separators (e.g. "SAMPLE:traceLevel=1;")
    becomes "jdbc:db2://host:port/SAMPLE:traceLevel=1;", letting the database
    segment toggle DB2 driver options (traceLevel/traceFile/traceDirectory/
    traceFileAppend) that bypass the Properties denylist. Same class of issue
    affects SQL Server (';' separator), Oracle (service-name slot), and the
    mysql:// family.
    
    Adds four layers of defense:
    
    1. SecurityUtils.checkDatabaseIsSafe(JdbcDriverType, database) rejects
       URL-option separators per driver family:
         DB2 -> : ; ? # &
         SQLSERVER -> ; ? # &
         ORACLE -> ? # &
         PG/MySQL/CK/DM/etc -> ? # & /
    
    2. Expand JDBC_DB2_BLOCKED_PARAMS with traceLevel/traceFile/
       traceDirectory/traceFileAppend so Properties-based injection of the
       same logging options is also blocked (defense in depth).
    
    3. Backfill value_regex for the `instance` field of every JDBC data
       source in linkis_dml.sql. RegExpParameterValidateStrategy skips
       validation when value_regex is NULL, so the previous schema offered
       no first-line defense. New regex: ^[A-Za-z0-9_.-]+$
    
    4. Same regex backfilled via UPDATE in the 1.9.0 upgrade script for
       existing installs.
    
    5. 6 new unit tests covering the DB2 database segment, the SQL Server
       and MySQL variants, benign-database sanity, and the expanded DB2
       denylist. All 24 tests in SecurityUtilsTest pass.
    
    Co-authored-by: Claude Opus 4.7 <[email protected]>
---
 .../apache/linkis/common/utils/SecurityUtils.java  |  66 ++++++++-
 .../linkis/common/utils/SecurityUtilsTest.java     | 154 +++++++++++++++++++++
 linkis-dist/package/db/linkis_dml.sql              |  26 ++--
 .../db/upgrade/1.9.0_schema/mysql/linkis_dml.sql   |   8 ++
 4 files changed, 239 insertions(+), 15 deletions(-)

diff --git 
a/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
 
b/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
index e8848aad28..3dca6c1f30 100644
--- 
a/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
+++ 
b/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
@@ -118,7 +118,10 @@ public abstract class SecurityUtils {
   private static final CommonVars<String> JDBC_DB2_BLOCKED_PARAMS =
       CommonVars$.MODULE$.apply(
           "linkis.jdbc.db2.blocked.params",
-          "clientRerouteServerListJNDIName,enableSeamlessFailover,JNDIName");
+          // traceLevel / traceFile / traceDirectory / traceFileAppend let the 
driver write trace
+          // output to arbitrary paths; blocked alongside the JNDI-related 
options.
+          "clientRerouteServerListJNDIName,enableSeamlessFailover,JNDIName,"
+              + "traceLevel,traceFile,traceDirectory,traceFileAppend");
 
   private static final CommonVars<String> JDBC_ORACLE_BLOCKED_PARAMS =
       CommonVars$.MODULE$.apply(
@@ -503,7 +506,9 @@ public abstract class SecurityUtils {
     // 2. Host sanity check: reject hosts that smuggle extra URL segments
     // (e.g. "host:port/evil?socketFactory=...").
     checkHostIsSafe(host);
-    // 3. Param denylist check (also handles URL-encoded bypass).
+    // 3. Database sanity check (reject URL option separators in the database 
segment).
+    checkDatabaseIsSafe(driverType, database);
+    // 4. Param denylist check (also handles URL-encoded bypass).
     checkDriverParams(driverType, extraParams);
   }
 
@@ -621,6 +626,63 @@ public abstract class SecurityUtils {
     }
   }
 
+  /**
+   * Reject database names that contain URL option separators. The 
metadata-query / datasource
+   * manager SqlConnection classes interpolate the user-supplied 
database/instance segment directly
+   * into the JDBC URL via String.format, so a value containing a separator 
character would be
+   * parsed as an extra URL option. Block the characters that any supported 
driver family treats as
+   * a delimiter after the database segment.
+   */
+  private static void checkDatabaseIsSafe(JdbcDriverType driverType, String 
database) {
+    if (StringUtils.isBlank(database)) {
+      return;
+    }
+    String trimmed = database.trim();
+    String forbidden;
+    switch (driverType) {
+      case DB2:
+        // DB2 URL option syntax is "jdbc:db2://h:p/db:opt1=v1;opt2=v2;".
+        forbidden = ":;?#&";
+        break;
+      case ORACLE:
+        // Oracle thin URL is "jdbc:oracle:thin:@//h:p/service" — ':' and '/' 
are structural, but
+        // '?' / '&' would only appear if the caller is abusing the 
service-name slot to inject
+        // query-style params. '#' is the fragment anchor and a known 
smuggling trick.
+        forbidden = "?#&";
+        break;
+      case SQLSERVER:
+        // SQL Server URL is "jdbc:sqlserver://h:p;databaseName=db;prop=v;" — 
';' is the property
+        // separator, so block it along with the usual query/fragment anchors.
+        forbidden = ";?#&";
+        break;
+      case POSTGRESQL:
+      case GREENPLUM:
+      case KINGBASE:
+      case CLICKHOUSE:
+      case DM:
+      case MYSQL:
+      case STARROCKS:
+      default:
+        // For the mysql:// family the database is followed by '?' for query 
params; for the others
+        // a '/' selects a path segment. Block all of the URL-meaningful 
characters.
+        forbidden = "?#&/";
+        break;
+    }
+    for (int i = 0; i < forbidden.length(); i++) {
+      char c = forbidden.charAt(i);
+      if (trimmed.indexOf(c) >= 0) {
+        throw new LinkisSecurityException(
+            35000,
+            "Database name contains forbidden character '"
+                + c
+                + "' for driver "
+                + driverType
+                + ": "
+                + trimmed);
+      }
+    }
+  }
+
   private static CommonVars<String> getDriverBlockedConfig(JdbcDriverType 
driverType) {
     switch (driverType) {
       case POSTGRESQL:
diff --git 
a/linkis-commons/linkis-common/src/test/java/org/apache/linkis/common/utils/SecurityUtilsTest.java
 
b/linkis-commons/linkis-common/src/test/java/org/apache/linkis/common/utils/SecurityUtilsTest.java
index 860bc8b154..06cc6d8fb9 100644
--- 
a/linkis-commons/linkis-common/src/test/java/org/apache/linkis/common/utils/SecurityUtilsTest.java
+++ 
b/linkis-commons/linkis-common/src/test/java/org/apache/linkis/common/utils/SecurityUtilsTest.java
@@ -533,4 +533,158 @@ public class SecurityUtilsTest {
     Assertions.assertEquals("linkis", props.getProperty("applicationName"));
     Assertions.assertEquals("u", props.getProperty("user"));
   }
+
+  // ----------------------- Database name sanitization tests 
-----------------------
+
+  @Test
+  public void testGenericCheck_Db2DatabaseInjection() {
+    // DB2 URL option syntax uses ':' and ';' as delimiters, so a database 
name containing them
+    // would be parsed as extra options. checkDatabaseIsSafe must reject them.
+    Map<String, Object> params = new HashMap<>();
+    params.put("k1", "v1");
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2, "localhost", 50000, "u", "p", 
"SAMPLE:traceLevel=1;", params));
+    // Same with a traceFile payload.
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2,
+                "localhost",
+                50000,
+                "u",
+                "p",
+                "SAMPLE:traceFile=/tmp/evil;",
+                params));
+    // Single-character URL separators must also be rejected individually.
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db;", 
params));
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db:opt=v", 
params));
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db?q=1", 
params));
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db#frag", 
params));
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2, "localhost", 50000, "u", "p", "db&k=v", 
params));
+  }
+
+  @Test
+  public void testGenericCheck_SqlserverDatabaseInjection() {
+    // SQL Server property separator is ';', reject it in the database name.
+    Map<String, Object> params = new HashMap<>();
+    params.put("k1", "v1");
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.SQLSERVER,
+                "localhost",
+                1433,
+                "u",
+                "p",
+                "db;trustServerCertificate=true",
+                params));
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.SQLSERVER, "localhost", 1433, "u", "p", 
"db?q=1", params));
+  }
+
+  @Test
+  public void testGenericCheck_MysqlAndPostgresDatabaseInjection() {
+    // The mysql:// family uses '?' / '&' for query params and '#' as the 
fragment anchor.
+    Map<String, Object> params = new HashMap<>();
+    params.put("k1", "v1");
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.MYSQL,
+                "localhost",
+                3306,
+                "u",
+                "p",
+                "db?autoDeserialize=true",
+                params));
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.POSTGRESQL,
+                "localhost",
+                5432,
+                "u",
+                "p",
+                "db?socketFactory=evil",
+                params));
+    // '/' is blocked for the mysql:// family because it selects a different 
path segment.
+    Assertions.assertThrows(
+        LinkisSecurityException.class,
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.POSTGRESQL, "localhost", 5432, "u", "p", 
"db/other", params));
+  }
+
+  @Test
+  public void testGenericCheck_BenignDatabaseNamesPass() {
+    // Sanity: legitimate database names for each driver family must still 
pass.
+    Map<String, Object> params = new HashMap<>();
+    Assertions.assertDoesNotThrow(
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2, "localhost", 50000, "u", "p", "SAMPLE", 
params));
+    Assertions.assertDoesNotThrow(
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.ORACLE, "localhost", 1521, "u", "p", "ORCL", 
params));
+    Assertions.assertDoesNotThrow(
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.POSTGRESQL, "localhost", 5432, "u", "p", 
"postgres", params));
+    Assertions.assertDoesNotThrow(
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.MYSQL, "localhost", 3306, "u", "p", "db_name", 
params));
+    Assertions.assertDoesNotThrow(
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.SQLSERVER, "localhost", 1433, "u", "p", 
"master", params));
+    // Blank database names are allowed (some drivers use a default).
+    Assertions.assertDoesNotThrow(
+        () ->
+            SecurityUtils.checkJdbcConnParams(
+                JdbcDriverType.DB2, "localhost", 50000, "u", "p", "  ", 
params));
+  }
+
+  @Test
+  public void testGenericCheck_Db2TraceParamsInDenylist() {
+    // The DB2 denylist must reject these even when they arrive via Properties 
rather than the URL.
+    assertDriverRejectsParam(JdbcDriverType.DB2, "traceLevel", "1");
+    assertDriverRejectsParam(JdbcDriverType.DB2, "traceFile", "/tmp/evil.log");
+    assertDriverRejectsParam(JdbcDriverType.DB2, "traceDirectory", "/tmp");
+    assertDriverRejectsParam(JdbcDriverType.DB2, "traceFileAppend", "true");
+    // JNDI-related params must remain in the denylist.
+    assertDriverRejectsParam(
+        JdbcDriverType.DB2, "clientRerouteServerListJNDIName", 
"ldap://evil/exp";);
+  }
 }
diff --git a/linkis-dist/package/db/linkis_dml.sql 
b/linkis-dist/package/db/linkis_dml.sql
index 6dd4ab0c86..eb4cb68037 100644
--- a/linkis-dist/package/db/linkis_dml.sql
+++ b/linkis-dist/package/db/linkis_dml.sql
@@ -679,7 +679,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'sid', 'SID', 'SID', NULL, 'TEXT', NULL, 0, 
'SID', 'SID', NULL, NULL, NULL, NULL,  now(), now()),
        (@data_source_type_id, 'serviceName', 'service_name', 'service_name', 
NULL, 'TEXT', NULL, 0, 'service_name', 'service_name', NULL, NULL, NULL, NULL,  
now(), now()),
        (@data_source_type_id, 'server', 'server', 'server', NULL, 'TEXT', 
NULL, 0, 'server', 'server', NULL, NULL, NULL, NULL,  now(), now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 0, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 0, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'dm';
 INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -691,7 +691,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'kingbase';
 INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -703,7 +703,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 -- https://jdbc.postgresql.org/documentation/use/
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'postgresql';
@@ -716,7 +716,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 -- 
https://learn.microsoft.com/zh-cn/sql/connect/jdbc/building-the-connection-url?redirectedfrom=MSDN&view=sql-server-ver16
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'sqlserver';
@@ -729,7 +729,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 -- 
https://www.ibm.com/docs/en/db2/11.5?topic=cdsudidsdjs-url-format-data-server-driver-jdbc-sqlj-type-4-connectivity
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'db2';
@@ -742,7 +742,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 -- 
https://greenplum.docs.pivotal.io/6-1/datadirect/datadirect_jdbc.html#topic_ylk_pbx_2bb
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'greenplum';
@@ -755,7 +755,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'doris';
 INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -767,7 +767,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 -- https://github.com/ClickHouse/clickhouse-jdbc/tree/master/clickhouse-jdbc
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'clickhouse';
@@ -780,7 +780,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'hive';
@@ -800,7 +800,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 0, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'starrocks';
 INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -812,7 +812,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 0, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'gaussdb';
 INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -824,7 +824,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'oceanbase';
 INSERT INTO `linkis_ps_dm_datasource_type_key`
@@ -836,7 +836,7 @@ VALUES (@data_source_type_id, 'address', '地址', 'Address', 
NULL, 'TEXT', NULL
        (@data_source_type_id, 'params', '连接参数(Connection params)', 'Connection 
params', NULL, 'TEXT', NULL, 0, '输入JSON格式(Input JSON format): 
{"param":"value"}', 'Input JSON format: {"param":"value"}', NULL, NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'username', '用户名(Username)', 'Username', NULL, 
'TEXT', NULL, 1, '用户名(Username)', 'Username', '^[0-9A-Za-z_-]+$', NULL, NULL, 
NULL,  now(), now()),
        (@data_source_type_id, 'password', '密码(Password)', 'Password', NULL, 
'PASSWORD', NULL, 1, '密码(Password)', 'Password', '', NULL, NULL, NULL,  now(), 
now()),
-       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', NULL, NULL, NULL, NULL,  now(), 
now());
+       (@data_source_type_id, 'instance', '实例名(instance)', 'Instance', NULL, 
'TEXT', NULL, 1, '实例名(instance)', 'Instance', '^[A-Za-z0-9_.-]+$', NULL, NULL, 
NULL, NULL,  now(), now());
 
 select @data_source_type_id := id from `linkis_ps_dm_datasource_type` where 
`name` = 'doris';
 UPDATE linkis_ps_dm_datasource_type_key SET `require` = 0 WHERE `key` 
="password" and `data_source_type_id` = @data_source_type_id;
diff --git a/linkis-dist/package/db/upgrade/1.9.0_schema/mysql/linkis_dml.sql 
b/linkis-dist/package/db/upgrade/1.9.0_schema/mysql/linkis_dml.sql
index e5625ca195..2c95812990 100644
--- a/linkis-dist/package/db/upgrade/1.9.0_schema/mysql/linkis_dml.sql
+++ b/linkis-dist/package/db/upgrade/1.9.0_schema/mysql/linkis_dml.sql
@@ -285,3 +285,11 @@ UPDATE `linkis_ps_configuration_config_key` SET 
default_value = '60' WHERE `key`
 -- 更新错误码正则表达式
 UPDATE linkis_ps_error_code SET error_regex = "The ecm of labels" WHERE 
error_code = "01001";
 
+-- Backfill value_regex for JDBC data-source `instance` fields.
+-- Restrict the instance field to identifier characters so 
RegExpParameterValidateStrategy
+-- rejects values containing URL option separators before they reach the 
connection layer.
+UPDATE `linkis_ps_dm_datasource_type_key`
+SET `value_regex` = '^[A-Za-z0-9_.-]+$'
+WHERE `key` = 'instance'
+  AND `value_regex` IS NULL;
+


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to