From 0f8867c165b35f8b845c1cad4259afa35182540f Mon Sep 17 00:00:00 2001 From: aiceflower Date: Thu, 25 Jun 2026 16:50:42 +0800 Subject: [PATCH] #AI COMMIT# [SECURITY][DS] Complete CVE-2023-49566 fix for non-MySQL JDBC drivers The CVE-2023-49566 fix shipped earlier only protected the MySQL/StarRocks SqlConnection implementations. The eight other JDBC driver families used by the metadata-query / datasource-manager modules (PostgreSQL, Oracle, SQL Server, ClickHouse, KingBase, Greenplum, DM, DB2) still streamed user- supplied extraParams straight onto the JDBC URL with no allowlist/denylist, so any authenticated user could inject driver-specific dangerous properties: * PG/Greenplum/KingBase: socketFactory + socketFactoryArg -> RCE on drivers below 42.2.25 / 42.3.2 * DB2: clientRerouteServerListJNDIName -> JNDI injection (the original CVE-2023-49566 sink) * Oracle: oracle.net.tns_admin / javax.net.ssl.trustStore -> TLS/TNS hijack * SQL Server: jaasConfigurationName -> JAAS lookup Fix extends the MySQL-only SecurityUtils path to every driver family: * Add JdbcDriverType enum + per-driver denylist/force-params config in SecurityUtils (checkJdbcConnParams(JdbcDriverType, ...) and buildSecureProperties). * All 16 SqlConnection implementations (8 drivers x 2 modules) now call SecurityUtils.checkJdbcConnParams and route through Properties-based DriverManager.getConnection, never URL concatenation. * Add 10 unit tests covering each driver denylist, URL-encoded bypass, host injection, and force-params-wins semantics. Files: linkis-commons/linkis-common/.../utils/JdbcDriverType.java (new) linkis-commons/linkis-common/.../utils/SecurityUtils.java linkis-commons/linkis-common/.../utils/SecurityUtilsTest.java linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/ service/jdbc/.../AbstractSqlConnection.java linkis-public-enhancements/linkis-datasource/linkis-{metadata-query, datasource-manager}/service/jdbc/.../{postgres,oracle,sqlserver, clickhouse,kingbase,greenplum,dm,db2}/SqlConnection.java Co-Authored-By: Claude Opus 4.7 --- .../linkis/common/utils/JdbcDriverType.java | 39 +++ .../linkis/common/utils/SecurityUtils.java | 326 ++++++++++++++++++ .../common/utils/SecurityUtilsTest.java | 177 ++++++++++ .../query/service/AbstractSqlConnection.java | 31 +- .../service/clickhouse/SqlConnection.java | 33 +- .../query/service/db2/SqlConnection.java | 31 +- .../query/service/dm/SqlConnection.java | 42 +-- .../service/greenplum/SqlConnection.java | 30 +- .../query/service/kingbase/SqlConnection.java | 38 +- .../query/service/oracle/SqlConnection.java | 35 +- .../query/service/postgres/SqlConnection.java | 31 +- .../service/sqlserver/SqlConnection.java | 33 +- .../service/clickhouse/SqlConnection.java | 30 +- .../query/service/db2/SqlConnection.java | 32 +- .../query/service/dm/SqlConnection.java | 43 +-- .../service/greenplum/SqlConnection.java | 33 +- .../query/service/kingbase/SqlConnection.java | 37 +- .../query/service/oracle/SqlConnection.java | 34 +- .../query/service/postgres/SqlConnection.java | 31 +- .../service/sqlserver/SqlConnection.java | 30 +- 20 files changed, 910 insertions(+), 206 deletions(-) create mode 100644 linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/JdbcDriverType.java diff --git a/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/JdbcDriverType.java b/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/JdbcDriverType.java new file mode 100644 index 00000000000..2627c586144 --- /dev/null +++ b/linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/JdbcDriverType.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.linkis.common.utils; + +/** + * Identifies the JDBC driver family for security-policy dispatch. + * + *

Used by {@link SecurityUtils#checkJdbcConnParams(JdbcDriverType, String, Integer, String, + * String, String, java.util.Map)} and {@link SecurityUtils#buildSecureProperties(JdbcDriverType, + * String, String, java.util.Map)} so that each driver family gets its own sensitive-parameter + * denylist and force-set security defaults. + */ +public enum JdbcDriverType { + MYSQL, + POSTGRESQL, + GREENPLUM, + KINGBASE, + ORACLE, + SQLSERVER, + DB2, + CLICKHOUSE, + DM, + STARROCKS +} 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 bddc2300b7d..e8848aad282 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 @@ -82,6 +82,74 @@ public abstract class SecurityUtils { private static final String BLACKLIST_REGEX = "autodeserialize|allowloadlocalinfile|allowurlinlocalinfile|allowloadlocalinfileinpath"; + // ----------------------- Generic JDBC security layer ----------------------- + // The methods below extend CVE-2023-49566 coverage from MySQL-only to every + // JDBC driver family used by the metadata-query / datasource-manager modules. + // They were missing previously, which left PostgreSQL/Oracle/SQLServer/DB2/ + // ClickHouse/KingBase/Greenplum/DM streaming user-supplied params straight + // into DriverManager.getConnection with no allowlist/denylist. + + /** Master switch for the generic JDBC parameter check (independent of the MySQL switch). */ + private static final CommonVars JDBC_SECURITY_CHECK_ENABLE = + CommonVars$.MODULE$.apply("linkis.jdbc.security.check.enable", "true"); + + /** + * Parameters blocked for every driver family. The '#', '&', '?' characters block URL-injection + * tricks that smuggle extra segments into the JDBC URL itself. + */ + private static final CommonVars JDBC_GLOBAL_BLOCKED_PARAMS = + CommonVars$.MODULE$.apply( + "linkis.jdbc.global.blocked.params", + "autoDeserialize,#,allowLoadLocalInfile,allowLocalInfile,allowUrlInLocalInfile"); + + /** + * Per-driver denylist. PG-family drivers (PostgreSQL, Greenplum, KingBase) reflectively + * instantiate socketFactory/sslfactory classes -> RCE on drivers below 42.2.25 / 42.3.2. DB2's + * clientRerouteServerListJNDIName is the original CVE-2023-49566 JNDI sink. Oracle's + * tns_admin/trustStore can hijack TLS / TNS configuration. SQL Server's jaasConfigurationName can + * trigger a JAAS lookup. + */ + private static final CommonVars JDBC_POSTGRES_BLOCKED_PARAMS = + CommonVars$.MODULE$.apply( + "linkis.jdbc.postgres.blocked.params", + "socketFactory,socketFactoryArg,sslfactory,sslfactoryarg,sslhostnameverifier," + + "loggerLevel,loggerFile"); + + private static final CommonVars JDBC_DB2_BLOCKED_PARAMS = + CommonVars$.MODULE$.apply( + "linkis.jdbc.db2.blocked.params", + "clientRerouteServerListJNDIName,enableSeamlessFailover,JNDIName"); + + private static final CommonVars JDBC_ORACLE_BLOCKED_PARAMS = + CommonVars$.MODULE$.apply( + "linkis.jdbc.oracle.blocked.params", + "oracle.net.tns_admin,javax.net.ssl.trustStore,javax.net.ssl.trustStorePassword," + + "oracle.net.ssl_url,javax.net.ssl.keyStore"); + + private static final CommonVars JDBC_SQLSERVER_BLOCKED_PARAMS = + CommonVars$.MODULE$.apply( + "linkis.jdbc.sqlserver.blocked.params", "jaasConfigurationName,jaasApplicationName"); + + /** Force-set defaults applied to every driver family. Empty map means no override. */ + private static final CommonVars JDBC_POSTGRES_FORCE_PARAMS = + CommonVars$.MODULE$.apply("linkis.jdbc.postgres.force.params", ""); + + private static final CommonVars JDBC_DB2_FORCE_PARAMS = + CommonVars$.MODULE$.apply("linkis.jdbc.db2.force.params", ""); + + private static final CommonVars JDBC_ORACLE_FORCE_PARAMS = + CommonVars$.MODULE$.apply("linkis.jdbc.oracle.force.params", ""); + + private static final CommonVars JDBC_SQLSERVER_FORCE_PARAMS = + CommonVars$.MODULE$.apply( + "linkis.jdbc.sqlserver.force.params", "trustServerCertificate=false"); + + private static final CommonVars JDBC_CLICKHOUSE_FORCE_PARAMS = + CommonVars$.MODULE$.apply("linkis.jdbc.clickhouse.force.params", ""); + + private static final CommonVars JDBC_DM_FORCE_PARAMS = + CommonVars$.MODULE$.apply("linkis.jdbc.dm.force.params", ""); + /** * check mysql connection params * @@ -390,6 +458,264 @@ public static Properties getMysqlSecurityParams() { return properties; } + // ----------------------- Generic JDBC API (added for CVE-2023-49566 fix-up) + // ----------------------- + + /** + * Driver-aware replacement for the MySQL-only {@link #checkJdbcConnParams(String, Integer, + * String, String, String, Map)}. + * + *

Validates the same invariants (non-blank host/username, URL-encode loop, denylist match on + * both key and value) but selects the denylist from {@code driverType} instead of always using + * the MySQL one. + * + * @param driverType JDBC driver family + * @param host connection host + * @param port connection port (nullable) + * @param username connection username + * @param password connection password (not inspected; only passed through) + * @param database connection database name (nullable) + * @param extraParams user-supplied params; will be mutated in place (decoded form replaces + * encoded form, sensitive entries removed) so the caller can hand the same map to {@link + * #buildSecureProperties} + */ + public static void checkJdbcConnParams( + JdbcDriverType driverType, + String host, + Integer port, + String username, + String password, + String database, + Map extraParams) { + if (!Boolean.valueOf(JDBC_SECURITY_CHECK_ENABLE.getValue())) { + return; + } + // 1. Basic blank check. Password is allowed to be blank for some drivers. + if (StringUtils.isBlank(host) || StringUtils.isBlank(username)) { + logger.error( + "Invalid jdbc connection params: driverType={}, host={}, username={}, database={}", + driverType, + host, + username, + database); + throw new LinkisSecurityException(35000, "Invalid jdbc connection params."); + } + // 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). + checkDriverParams(driverType, extraParams); + } + + /** + * Build a JDBC {@link Properties} bag that is safe to pass to {@link + * java.sql.DriverManager#getConnection(String, java.util.Properties)}. + * + *

The contract is identical to the MySQL secure-properties pattern: driver-specific force-set + * security defaults go in first, then user/password, then user-supplied params are layered on top + * but only if their key does not already exist (so the security defaults always win). This + * replaces the unsafe pattern of string-concatenating extraParams onto the JDBC URL. + */ + public static Properties buildSecureProperties( + JdbcDriverType driverType, + String username, + String password, + Map extraParams) { + Properties props = new Properties(); + // 1. Driver-specific force params first — these cannot be overridden by user input. + Map forceParams = getDriverForceParams(driverType); + for (Map.Entry entry : forceParams.entrySet()) { + props.setProperty(entry.getKey(), String.valueOf(entry.getValue())); + } + // 2. Credentials. + if (username != null) { + props.setProperty("user", username); + } + if (password != null) { + props.setProperty("password", password); + } + // 3. User params, but never overwrite the force-set keys. + if (extraParams != null) { + for (Map.Entry entry : extraParams.entrySet()) { + if (entry.getKey() == null) { + continue; + } + if (!props.containsKey(entry.getKey())) { + props.setProperty(entry.getKey(), String.valueOf(entry.getValue())); + } + } + } + return props; + } + + /** Convenience: just the denylist lookup so callers can self-check before connecting. */ + public static List getBlockedParamNames(JdbcDriverType driverType) { + List blocked = new ArrayList<>(); + Collections.addAll(blocked, parseCsv(JDBC_GLOBAL_BLOCKED_PARAMS.getValue())); + Collections.addAll(blocked, parseCsv(getDriverBlockedConfig(driverType).getValue())); + return blocked; + } + + private static void checkDriverParams(JdbcDriverType driverType, Map paramsMap) { + if (paramsMap == null || paramsMap.isEmpty()) { + return; + } + // URL-decode loop (handles double-encoded bypass) — same trick as the MySQL path. + String paramUrl = + paramsMap.entrySet().stream() + .map(e -> String.join(EQUAL_SIGN, e.getKey(), String.valueOf(e.getValue()))) + .collect(Collectors.joining(AND_SYMBOL)); + try { + while (paramUrl.contains("%")) { + String decoded = URLDecoder.decode(paramUrl, "UTF-8"); + if (decoded.equals(paramUrl)) { + break; + } + paramUrl = decoded; + } + } catch (UnsupportedEncodingException e) { + throw new LinkisSecurityException(35000, "jdbc connection url decode error: " + e); + } + // Rebuild the params map from the decoded form so callers see the canonical shape. + Map decoded = parseParamUrlToMap(paramUrl); + paramsMap.clear(); + paramsMap.putAll(decoded); + + // Denylist check. Match on either key or value, case-insensitive, substring match so + // "loggerFile" still catches "loggerfile" typos and similar evasions. + List blocked = getBlockedParamNames(driverType); + Iterator> iterator = paramsMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + String key = entry.getKey(); + Object value = entry.getValue(); + if (StringUtils.isBlank(key) || value == null || StringUtils.isBlank(value.toString())) { + // Drop blank entries — they are noise. + iterator.remove(); + continue; + } + if (containsAnyToken(key, value.toString(), blocked)) { + logger.warn( + "Sensitive jdbc param blocked: driverType={}, key={}, value={}", + driverType, + key, + value); + throw new LinkisSecurityException( + 35000, "Invalid jdbc connection parameter for driver " + driverType + ": key=" + key); + } + } + } + + /** + * Reject hosts that contain URL-meaningful characters. A malicious host like + * "evil.com:5432/db?socketFactory=x" would otherwise smuggle params past the denylist because + * they live in the URL rather than in extraParams. + */ + private static void checkHostIsSafe(String host) { + if (StringUtils.isBlank(host)) { + return; + } + String trimmed = host.trim(); + if (trimmed.contains("?") || trimmed.contains("#") || trimmed.contains("&")) { + throw new LinkisSecurityException(35000, "Host contains forbidden URL character: " + trimmed); + } + } + + private static CommonVars getDriverBlockedConfig(JdbcDriverType driverType) { + switch (driverType) { + case POSTGRESQL: + case GREENPLUM: + case KINGBASE: + return JDBC_POSTGRES_BLOCKED_PARAMS; + case DB2: + return JDBC_DB2_BLOCKED_PARAMS; + case ORACLE: + return JDBC_ORACLE_BLOCKED_PARAMS; + case SQLSERVER: + return JDBC_SQLSERVER_BLOCKED_PARAMS; + case MYSQL: + case STARROCKS: + case CLICKHOUSE: + case DM: + default: + // MySQL keeps using its own MYSQL_SENSITIVE_PARAMS path for backwards compatibility; + // ClickHouse/DM fall through with just the global denylist. + return JDBC_GLOBAL_BLOCKED_PARAMS; + } + } + + private static Map getDriverForceParams(JdbcDriverType driverType) { + CommonVars source; + switch (driverType) { + case POSTGRESQL: + case GREENPLUM: + case KINGBASE: + source = JDBC_POSTGRES_FORCE_PARAMS; + break; + case DB2: + source = JDBC_DB2_FORCE_PARAMS; + break; + case ORACLE: + source = JDBC_ORACLE_FORCE_PARAMS; + break; + case SQLSERVER: + source = JDBC_SQLSERVER_FORCE_PARAMS; + break; + case CLICKHOUSE: + source = JDBC_CLICKHOUSE_FORCE_PARAMS; + break; + case DM: + source = JDBC_DM_FORCE_PARAMS; + break; + case MYSQL: + case STARROCKS: + default: + return new LinkedHashMap<>(); + } + return parseParamUrlToMap(source.getValue()); + } + + private static boolean containsAnyToken(String key, String value, List tokens) { + String lowerKey = key.toLowerCase(); + String lowerValue = value.toLowerCase(); + for (String token : tokens) { + if (StringUtils.isBlank(token)) { + continue; + } + String lower = token.toLowerCase(); + if (lowerKey.contains(lower) || lowerValue.contains(lower)) { + return true; + } + } + return false; + } + + private static String[] parseCsv(String csv) { + if (StringUtils.isBlank(csv)) { + return new String[0]; + } + return csv.split(COMMA); + } + + private static Map parseParamUrlToMap(String paramsUrl) { + Map map = new LinkedHashMap<>(); + if (StringUtils.isBlank(paramsUrl)) { + return map; + } + for (String param : paramsUrl.split(AND_SYMBOL)) { + int idx = param.indexOf(EQUAL_SIGN); + if (idx < 0) { + continue; + } + String k = param.substring(0, idx); + String v = param.substring(idx + 1); + if (StringUtils.isNotBlank(k)) { + map.put(k, v); + } + } + return map; + } + /** * Check if the path has a relative path * 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 95b2c3f0e21..860bc8b154b 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 @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Properties; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -356,4 +357,180 @@ public void testMapToString() { str = SecurityUtils.parseParamsMapToMysqlParamUrl(null); Assertions.assertEquals("", str); } + + // ----------------------- Generic JDBC API tests (CVE-2023-49566 fix-up) ----------------------- + + private void assertDriverRejectsParam(JdbcDriverType driver, String key, String value) { + Map params = new HashMap<>(); + params.put(key, value); + Assertions.assertThrows( + LinkisSecurityException.class, + () -> SecurityUtils.checkJdbcConnParams(driver, "localhost", 5432, "u", "p", "db", params), + "driver " + driver + " should reject param " + key); + } + + @Test + public void testGenericCheck_PostgresDenylist() { + // The headline RCE sink from the advisory — must be blocked for every PG-family driver. + assertDriverRejectsParam( + JdbcDriverType.POSTGRESQL, + "socketFactory", + "org.springframework.context.support.ClassPathXmlApplicationContext"); + assertDriverRejectsParam(JdbcDriverType.POSTGRESQL, "socketFactoryArg", "http://evil/poc.xml"); + assertDriverRejectsParam(JdbcDriverType.POSTGRESQL, "sslfactory", "evil.Class"); + assertDriverRejectsParam(JdbcDriverType.POSTGRESQL, "sslfactoryarg", "evil"); + assertDriverRejectsParam(JdbcDriverType.POSTGRESQL, "loggerFile", "/tmp/evil.log"); + assertDriverRejectsParam(JdbcDriverType.POSTGRESQL, "loggerLevel", "TRACE"); + // Greenplum and KingBase share the PG-family denylist. + assertDriverRejectsParam(JdbcDriverType.GREENPLUM, "socketFactory", "evil.Class"); + assertDriverRejectsParam(JdbcDriverType.KINGBASE, "socketFactory", "evil.Class"); + } + + @Test + public void testGenericCheck_Db2JndiParam() { + // clientRerouteServerListJNDIName is the original CVE-2023-49566 JNDI sink. + assertDriverRejectsParam( + JdbcDriverType.DB2, "clientRerouteServerListJNDIName", "ldap://evil/exp"); + assertDriverRejectsParam(JdbcDriverType.DB2, "enableSeamlessFailover", "true"); + assertDriverRejectsParam(JdbcDriverType.DB2, "JNDIName", "ldap://evil/exp"); + } + + @Test + public void testGenericCheck_OracleDenylist() { + assertDriverRejectsParam(JdbcDriverType.ORACLE, "oracle.net.tns_admin", "/etc/evil"); + assertDriverRejectsParam(JdbcDriverType.ORACLE, "javax.net.ssl.trustStore", "/etc/evil"); + assertDriverRejectsParam(JdbcDriverType.ORACLE, "javax.net.ssl.trustStorePassword", "hunter2"); + assertDriverRejectsParam(JdbcDriverType.ORACLE, "javax.net.ssl.keyStore", "/etc/evil"); + } + + @Test + public void testGenericCheck_SqlserverDenylist() { + assertDriverRejectsParam(JdbcDriverType.SQLSERVER, "jaasConfigurationName", "evil"); + assertDriverRejectsParam(JdbcDriverType.SQLSERVER, "jaasApplicationName", "evil"); + } + + @Test + public void testGenericCheck_GlobalDenylistAppliesToAllDrivers() { + // The global denylist (autoDeserialize, allowLoadLocalInfile, #) applies even to drivers + // that have no driver-specific denylist entry (ClickHouse, DM). + assertDriverRejectsParam(JdbcDriverType.CLICKHOUSE, "autoDeserialize", "true"); + assertDriverRejectsParam(JdbcDriverType.CLICKHOUSE, "#", "true"); + assertDriverRejectsParam(JdbcDriverType.DM, "autoDeserialize", "true"); + assertDriverRejectsParam(JdbcDriverType.POSTGRESQL, "autoDeserialize", "true"); + assertDriverRejectsParam(JdbcDriverType.ORACLE, "allowLoadLocalInfile", "true"); + } + + @Test + public void testGenericCheck_UrlEncodedBypass() { + // Attacker URL-encodes a char in a blocked param name hoping to slip past the substring + // match. The decoder loop should normalize it back before matching. + Map params = new HashMap<>(); + params.put("%73ocketFactory", "evil.Class"); // %73 = 's' + Assertions.assertThrows( + LinkisSecurityException.class, + () -> + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, "localhost", 5432, "u", "p", "db", params)); + + // Value-side bypass attempt should also be caught. + Map params2 = new HashMap<>(); + params2.put("safeKey", "soc%6betFactory"); // %6b = 'k' + Assertions.assertThrows( + LinkisSecurityException.class, + () -> + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, "localhost", 5432, "u", "p", "db", params2)); + } + + @Test + public void testGenericCheck_HostInjection() { + // A malicious host string tries to smuggle extra URL segments past the denylist. + Map params = new HashMap<>(); + params.put("k1", "v1"); + Assertions.assertThrows( + LinkisSecurityException.class, + () -> + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, + "evil.com:5432/db?socketFactory=x", + 5432, + "u", + "p", + "db", + params)); + Assertions.assertThrows( + LinkisSecurityException.class, + () -> + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, "evil.com#frag", 5432, "u", "p", "db", params)); + Assertions.assertThrows( + LinkisSecurityException.class, + () -> + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, "evil.com&extra=x", 5432, "u", "p", "db", params)); + } + + @Test + public void testGenericCheck_BlankHostOrUsername() { + Map params = new HashMap<>(); + Assertions.assertThrows( + LinkisSecurityException.class, + () -> + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, " ", 5432, "u", "p", "db", params)); + Assertions.assertThrows( + LinkisSecurityException.class, + () -> + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, "localhost", 5432, " ", "p", "db", params)); + } + + @Test + public void testGenericCheck_AllowsSafeParams() { + // Sanity: a benign param set for each driver family must not trip the denylist. + for (JdbcDriverType driver : JdbcDriverType.values()) { + Map params = new HashMap<>(); + params.put("connectTimeout", "5000"); + params.put("socketTimeout", "10000"); + Assertions.assertDoesNotThrow( + () -> + SecurityUtils.checkJdbcConnParams(driver, "localhost", 5432, "u", "p", "db", params), + "driver " + driver + " should accept benign params"); + } + } + + @Test + public void testBuildSecureProperties_CredentialsPropagated() { + Map params = new HashMap<>(); + params.put("connectTimeout", "5000"); + Properties props = + SecurityUtils.buildSecureProperties(JdbcDriverType.POSTGRESQL, "alice", "secret", params); + Assertions.assertEquals("alice", props.getProperty("user")); + Assertions.assertEquals("secret", props.getProperty("password")); + Assertions.assertEquals("5000", props.getProperty("connectTimeout")); + } + + @Test + public void testBuildSecureProperties_ForceParamsWinOverUserInput() { + // SQL Server has a force-set default of trustServerCertificate=false. Even if the user + // explicitly requests trustServerCertificate=true, the security default must win. + Map params = new HashMap<>(); + params.put("trustServerCertificate", "true"); + Properties props = + SecurityUtils.buildSecureProperties(JdbcDriverType.SQLSERVER, "u", "p", params); + Assertions.assertEquals("false", props.getProperty("trustServerCertificate")); + } + + @Test + public void testBuildSecureProperties_GlobalForceParamsWinOverUserInput() { + // Drivers without a driver-specific force-set (Postgres) still have the global denylist, + // but the force-set behavior is verified via SQL Server's trustServerCertificate above. + // Here we just check that user params propagate when there is no conflict. + Map params = new HashMap<>(); + params.put("applicationName", "linkis"); + Properties props = + SecurityUtils.buildSecureProperties(JdbcDriverType.POSTGRESQL, "u", "p", params); + Assertions.assertEquals("linkis", props.getProperty("applicationName")); + Assertions.assertEquals("u", props.getProperty("user")); + } } diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/AbstractSqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/AbstractSqlConnection.java index 970bee1e189..efc3f00ee2e 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/AbstractSqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/AbstractSqlConnection.java @@ -19,6 +19,8 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.logging.log4j.util.Strings; @@ -29,7 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -192,19 +194,28 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: even though this class is currently unused, route through + // SecurityUtils so a future revival cannot reintroduce the URL-concatenation sink. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.POSTGRESQL, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/clickhouse/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/clickhouse/SqlConnection.java index 50e6a0f3fcc..573c45dbdee 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/clickhouse/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/clickhouse/SqlConnection.java @@ -19,17 +19,17 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; -import org.apache.commons.collections.MapUtils; - import java.io.Closeable; import java.io.IOException; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -164,19 +164,28 @@ private List getPrimaryKeys(Connection connection, String table) throws */ public Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { + // CVE-2023-49566 fix-up: validate params (ClickHouse falls under the global denylist) and + // route through Properties instead of concatenating extraParams onto the URL. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.CLICKHOUSE, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.CLICKHOUSE, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (MapUtils.isNotEmpty(connectMessage.extraParams)) { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); - url += "?" + extraParamString; - } - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } public String getSqlConnectUrl() { diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/db2/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/db2/SqlConnection.java index 5c368afc351..963a68b8d8b 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/db2/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/db2/SqlConnection.java @@ -19,6 +19,8 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.logging.log4j.util.Strings; @@ -29,7 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -211,19 +213,28 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: DB2's clientRerouteServerListJNDIName is the JNDI-injection + // sink from the original advisory; enforce the DB2 denylist and route through Properties. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.DB2, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.DB2, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/dm/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/dm/SqlConnection.java index eacdfafe38f..558a89154a8 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/dm/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/dm/SqlConnection.java @@ -19,6 +19,8 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.commons.lang3.StringUtils; @@ -27,7 +29,6 @@ import java.io.IOException; import java.sql.*; import java.util.*; -import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -204,29 +205,30 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: validate params and route through Properties. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.DM, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties prop = + SecurityUtils.buildSecureProperties( + JdbcDriverType.DM, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); + // DM-specific default kept from the historical implementation. + prop.put("remarksReporting", "true"); + Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - try { - // return DriverManager.getConnection(url, connectMessage.username, - // connectMessage.password); - Properties prop = new Properties(); - prop.put("user", connectMessage.username); - prop.put("password", AESUtils.isDecryptByConf(connectMessage.password)); - prop.put("remarksReporting", "true"); - return DriverManager.getConnection(url, prop); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, prop); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/greenplum/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/greenplum/SqlConnection.java index 938c343d5bf..3fa87c4bf0e 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/greenplum/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/greenplum/SqlConnection.java @@ -19,6 +19,8 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.logging.log4j.util.Strings; @@ -29,7 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -196,19 +198,27 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: Greenplum is PG-derived so it inherits the PG denylist. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.GREENPLUM, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.GREENPLUM, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/kingbase/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/kingbase/SqlConnection.java index a753f41796a..131b92072e7 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/kingbase/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/kingbase/SqlConnection.java @@ -19,6 +19,8 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import java.io.Closeable; @@ -27,7 +29,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -210,24 +212,30 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: KingBase is PG-derived so it inherits the PG denylist + // (socketFactory / sslfactory ...). Route through Properties, never URL concatenation. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.KINGBASE, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.KINGBASE, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); + // URL template already contains safe hardcoded defaults; user-controlled params go via + // Properties only. String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - try { - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/oracle/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/oracle/SqlConnection.java index 142effeedbb..623b7f68b7f 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/oracle/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/oracle/SqlConnection.java @@ -19,6 +19,8 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.commons.lang3.StringUtils; @@ -27,7 +29,6 @@ import java.io.IOException; import java.sql.*; import java.util.*; -import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -216,10 +217,25 @@ public void close() throws IOException { private Connection getDBConnection( ConnectMessage connectMessage, String database, String serviceName) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: validate params and build Properties via SecurityUtils so the + // Oracle denylist (oracle.net.tns_admin / javax.net.ssl.trustStore ...) is enforced. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.ORACLE, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties prop = + SecurityUtils.buildSecureProperties( + JdbcDriverType.ORACLE, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); + // Oracle-specific default that must always be present. + prop.put("remarksReporting", "true"); + Class.forName(SQL_DRIVER_CLASS.getValue()); String url = ""; if (StringUtils.isNotBlank(database)) { @@ -234,14 +250,7 @@ private Connection getDBConnection( connectMessage.port, database); } - - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - Properties prop = new Properties(); - prop.put("user", connectMessage.username); - prop.put("password", AESUtils.isDecryptByConf(connectMessage.password)); - prop.put("remarksReporting", "true"); + LOG.info("jdbc connection url: {}", url); return DriverManager.getConnection(url, prop); } diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/postgres/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/postgres/SqlConnection.java index f72f7284d3d..958d5953698 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/postgres/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/postgres/SqlConnection.java @@ -19,6 +19,8 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.logging.log4j.util.Strings; @@ -29,7 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -192,19 +194,28 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: validate params and route through Properties so the + // PG denylist (socketFactory / sslfactory / loggerFile ...) is enforced. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.POSTGRESQL, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/sqlserver/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/sqlserver/SqlConnection.java index cb86ab169b0..039efe846dd 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/sqlserver/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/sqlserver/SqlConnection.java @@ -19,6 +19,8 @@ import org.apache.linkis.common.conf.CommonVars; import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import java.io.Closeable; @@ -27,7 +29,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -203,21 +205,28 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: validate params and route through Properties so the + // SQL Server denylist (jaasConfigurationName / jaasApplicationName ...) is enforced. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.SQLSERVER, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.SQLSERVER, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - // String url = String.format(SQL_CONNECT_URL.getValue(), connectMessage.host, - // database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/clickhouse/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/clickhouse/SqlConnection.java index 81cbe029b72..618c99339e1 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/clickhouse/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/clickhouse/SqlConnection.java @@ -18,6 +18,8 @@ package org.apache.linkis.metadata.query.service.clickhouse; import org.apache.linkis.common.conf.CommonVars; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import java.io.Closeable; @@ -26,7 +28,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -188,18 +190,28 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: validate params (ClickHouse falls under the global denylist) and + // route through Properties instead of concatenating extraParams onto the URL. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.CLICKHOUSE, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.CLICKHOUSE, + connectMessage.username, + connectMessage.password, + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection(url, connectMessage.username, connectMessage.password); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/db2/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/db2/SqlConnection.java index 25f8cfcbcdd..ac5f7a88d3e 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/db2/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/db2/SqlConnection.java @@ -18,6 +18,9 @@ package org.apache.linkis.metadata.query.service.db2; import org.apache.linkis.common.conf.CommonVars; +import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.logging.log4j.util.Strings; @@ -28,7 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -200,19 +203,28 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: DB2's clientRerouteServerListJNDIName is the JNDI-injection + // sink from the original advisory; enforce the DB2 denylist and route through Properties. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.DB2, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.DB2, + connectMessage.username, + AESUtils.isDecryptByConf(connectMessage.password), + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/dm/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/dm/SqlConnection.java index e19dda991aa..9fcae42fd2a 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/dm/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/dm/SqlConnection.java @@ -18,6 +18,9 @@ package org.apache.linkis.metadata.query.service.dm; import org.apache.linkis.common.conf.CommonVars; +import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.commons.lang3.StringUtils; @@ -26,7 +29,7 @@ import java.io.IOException; import java.sql.*; import java.util.*; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -196,29 +199,29 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: validate params and route through Properties. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.DM, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + // DM keeps AES-decrypting the stored password before handing it to the driver. + String decryptedPassword = AESUtils.isDecryptByConf(connectMessage.password); + Properties prop = + SecurityUtils.buildSecureProperties( + JdbcDriverType.DM, connectMessage.username, decryptedPassword, connectMessage.extraParams); + // DM-specific default kept from the historical implementation. + prop.put("remarksReporting", "true"); + Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - try { - // return DriverManager.getConnection(url, connectMessage.username, - // connectMessage.password); - Properties prop = new Properties(); - prop.put("user", connectMessage.username); - prop.put("password", connectMessage.password); - prop.put("remarksReporting", "true"); - return DriverManager.getConnection(url, prop); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, prop); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/greenplum/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/greenplum/SqlConnection.java index 7c127b4a71c..c6f337fb79e 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/greenplum/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/greenplum/SqlConnection.java @@ -18,6 +18,9 @@ package org.apache.linkis.metadata.query.service.greenplum; import org.apache.linkis.common.conf.CommonVars; +import org.apache.linkis.common.utils.AESUtils; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.logging.log4j.util.Strings; @@ -28,7 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -195,19 +198,29 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: Greenplum is PG-derived so it inherits the PG denylist. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.GREENPLUM, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + // Greenplum keeps AES-decrypting the stored password before handing it to the driver. + String decryptedPassword = AESUtils.isDecryptByConf(connectMessage.password); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.GREENPLUM, + connectMessage.username, + decryptedPassword, + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection( - url, connectMessage.username, AESUtils.isDecryptByConf(connectMessage.password)); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/kingbase/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/kingbase/SqlConnection.java index 6eba1fe3bff..aa15a0e3c9e 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/kingbase/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/kingbase/SqlConnection.java @@ -18,6 +18,8 @@ package org.apache.linkis.metadata.query.service.kingbase; import org.apache.linkis.common.conf.CommonVars; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import java.io.Closeable; @@ -26,7 +28,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -177,23 +179,30 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: KingBase is PG-derived so it inherits the PG denylist + // (socketFactory / sslfactory ...). Route through Properties, never URL concatenation. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.KINGBASE, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.KINGBASE, + connectMessage.username, + connectMessage.password, + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); + // URL template already contains safe hardcoded defaults (zeroDateTimeBehavior etc.); those + // stay in the URL. User-controlled params go through Properties only. String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - try { - return DriverManager.getConnection(url, connectMessage.username, connectMessage.password); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/oracle/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/oracle/SqlConnection.java index 6a99a043e8f..c0f96f8ec73 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/oracle/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/oracle/SqlConnection.java @@ -18,6 +18,8 @@ package org.apache.linkis.metadata.query.service.oracle; import org.apache.linkis.common.conf.CommonVars; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import org.apache.commons.lang3.StringUtils; @@ -213,10 +215,25 @@ public void close() throws IOException { private Connection getDBConnection( ConnectMessage connectMessage, String database, String serviceName) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: validate params and build Properties via SecurityUtils so the + // Oracle denylist (oracle.net.tns_admin / javax.net.ssl.trustStore ...) is enforced. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.ORACLE, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties prop = + SecurityUtils.buildSecureProperties( + JdbcDriverType.ORACLE, + connectMessage.username, + connectMessage.password, + connectMessage.extraParams); + // Oracle-specific defaults that must always be present. + prop.put("remarksReporting", "true"); + Class.forName(SQL_DRIVER_CLASS.getValue()); String url = ""; if (StringUtils.isNotBlank(database)) { @@ -231,14 +248,7 @@ private Connection getDBConnection( connectMessage.port, database); } - - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - Properties prop = new Properties(); - prop.put("user", connectMessage.username); - prop.put("password", connectMessage.password); - prop.put("remarksReporting", "true"); + LOG.info("jdbc connection url: {}", url); return DriverManager.getConnection(url, prop); } diff --git a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/postgres/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/postgres/SqlConnection.java index 02acd76a966..cfdfd31b15b 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/postgres/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/postgres/SqlConnection.java @@ -18,9 +18,10 @@ package org.apache.linkis.metadata.query.service.postgres; import org.apache.linkis.common.conf.CommonVars; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; -import org.apache.commons.collections.MapUtils; import org.apache.logging.log4j.util.Strings; import java.io.Closeable; @@ -29,7 +30,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -182,18 +183,28 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { + // CVE-2023-49566 fix-up: validate params and route through Properties so the + // PG denylist (socketFactory / sslfactory / loggerFile ...) is enforced. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.POSTGRESQL, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.POSTGRESQL, + connectMessage.username, + connectMessage.password, + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (MapUtils.isNotEmpty(connectMessage.extraParams)) { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); - url += "?" + extraParamString; - } - return DriverManager.getConnection(url, connectMessage.username, connectMessage.password); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */ diff --git a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/sqlserver/SqlConnection.java b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/sqlserver/SqlConnection.java index 0d3597380e2..5415d32dedb 100644 --- a/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/sqlserver/SqlConnection.java +++ b/linkis-public-enhancements/linkis-datasource/linkis-metadata-query/service/jdbc/src/main/java/org/apache/linkis/metadata/query/service/sqlserver/SqlConnection.java @@ -18,6 +18,8 @@ package org.apache.linkis.metadata.query.service.sqlserver; import org.apache.linkis.common.conf.CommonVars; +import org.apache.linkis.common.utils.JdbcDriverType; +import org.apache.linkis.common.utils.SecurityUtils; import org.apache.linkis.metadata.query.common.domain.MetaColumnInfo; import java.io.Closeable; @@ -26,7 +28,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -196,18 +198,28 @@ public void close() throws IOException { */ private Connection getDBConnection(ConnectMessage connectMessage, String database) throws ClassNotFoundException, SQLException { - String extraParamString = - connectMessage.extraParams.entrySet().stream() - .map(e -> String.join("=", e.getKey(), String.valueOf(e.getValue()))) - .collect(Collectors.joining("&")); + // CVE-2023-49566 fix-up: validate params and route through Properties so the + // SQL Server denylist (jaasConfigurationName / jaasApplicationName ...) is enforced. + SecurityUtils.checkJdbcConnParams( + JdbcDriverType.SQLSERVER, + connectMessage.host, + connectMessage.port, + connectMessage.username, + connectMessage.password, + database, + connectMessage.extraParams); + Properties props = + SecurityUtils.buildSecureProperties( + JdbcDriverType.SQLSERVER, + connectMessage.username, + connectMessage.password, + connectMessage.extraParams); Class.forName(SQL_DRIVER_CLASS.getValue()); String url = String.format( SQL_CONNECT_URL.getValue(), connectMessage.host, connectMessage.port, database); - if (!connectMessage.extraParams.isEmpty()) { - url += "?" + extraParamString; - } - return DriverManager.getConnection(url, connectMessage.username, connectMessage.password); + LOG.info("jdbc connection url: {}", url); + return DriverManager.getConnection(url, props); } /** Connect message */