Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for ClickHouse sql injection by removing ability to have expression in table options #16261

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

import static com.clickhouse.data.ClickHouseValues.convertToQuotedString;
import static com.google.common.base.Preconditions.checkArgument;
Expand Down Expand Up @@ -299,7 +300,7 @@ protected String createTableSql(RemoteTableName remoteTableName, List<String> co
formatProperty(ClickHouseTableProperties.getOrderBy(tableProperties)).ifPresent(value -> tableOptions.add("ORDER BY " + value));
formatProperty(ClickHouseTableProperties.getPrimaryKey(tableProperties)).ifPresent(value -> tableOptions.add("PRIMARY KEY " + value));
formatProperty(ClickHouseTableProperties.getPartitionBy(tableProperties)).ifPresent(value -> tableOptions.add("PARTITION BY " + value));
ClickHouseTableProperties.getSampleBy(tableProperties).ifPresent(value -> tableOptions.add("SAMPLE BY " + value));
ClickHouseTableProperties.getSampleBy(tableProperties).ifPresent(value -> tableOptions.add("SAMPLE BY " + quoted(value)));
tableMetadata.getComment().ifPresent(comment -> tableOptions.add(format("COMMENT %s", clickhouseVarcharLiteral(comment))));

return format("CREATE TABLE %s (%s) %s", quoted(remoteTableName), join(", ", columns), join(" ", tableOptions.build()));
Expand Down Expand Up @@ -363,7 +364,7 @@ public void setTableProperties(ConnectorSession session, JdbcTableHandle handle,
.collect(toImmutableMap(Entry::getKey, entry -> entry.getValue().orElseThrow()));

ImmutableList.Builder<String> tableOptions = ImmutableList.builder();
ClickHouseTableProperties.getSampleBy(properties).ifPresent(value -> tableOptions.add("SAMPLE BY " + value));
ClickHouseTableProperties.getSampleBy(properties).ifPresent(value -> tableOptions.add("SAMPLE BY " + quoted(value)));

try (Connection connection = connectionFactory.openConnection(session)) {
String sql = format(
Expand Down Expand Up @@ -720,10 +721,10 @@ private Optional<String> formatProperty(List<String> prop)
}
if (prop.size() == 1) {
// only one column
return Optional.of(prop.get(0));
return Optional.of(quoted(prop.get(0)));
}
// include more than one column
return Optional.of("(" + String.join(",", prop) + ")");
return Optional.of(prop.stream().map(this::quoted).collect(Collectors.joining(",", "(", ")")));
}

private static LongWriteFunction uInt8WriteFunction(ClickHouseVersion version)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior)
}
}

@Test
public void testSampleBySqlInjection()
{
assertQueryFails("CREATE TABLE test (p1 int NOT NULL, p2 boolean NOT NULL, x VARCHAR) WITH (engine = 'MergeTree', order_by = ARRAY['p1', 'p2'], primary_key = ARRAY['p1', 'p2'], sample_by = 'p2; drop table tpch.nation')", "(?s).*Missing columns: 'p2; drop table tpch.nation.*");
assertUpdate("CREATE TABLE test (p1 int NOT NULL, p2 boolean NOT NULL, x VARCHAR) WITH (engine = 'MergeTree', order_by = ARRAY['p1', 'p2'], primary_key = ARRAY['p1', 'p2'], sample_by = 'p2')");
assertQueryFails("ALTER TABLE test SET PROPERTIES sample_by = 'p2; drop table tpch.nation'", "(?s).*Missing columns: 'p2; drop table tpch.nation.*");
assertUpdate("ALTER TABLE test SET PROPERTIES sample_by = 'p2'");
}

@Override
@Test(dataProvider = "testColumnNameDataProvider")
public void testColumnName(String columnName)
Expand Down Expand Up @@ -352,7 +361,7 @@ public void testDifferentEngine()

// MergeTree with optional
assertUpdate("CREATE TABLE " + tableName + " (id int NOT NULL, x VARCHAR, logdate DATE NOT NULL) WITH " +
"(engine = 'MergeTree', order_by = ARRAY['id'], partition_by = ARRAY['toYYYYMM(logdate)'])");
"(engine = 'MergeTree', order_by = ARRAY['id'], partition_by = ARRAY['logdate'])");
assertTrue(getQueryRunner().tableExists(getSession(), tableName));
assertUpdate("DROP TABLE " + tableName);

Expand Down