Skip to content

Commit b7007cd

Browse files
committed
fix:codeql scan Security issue
1 parent a427f91 commit b7007cd

1 file changed

Lines changed: 105 additions & 43 deletions

File tree

‎base/src/main/java/com/tinyengine/it/dynamic/service/DynamicModelService.java‎

Lines changed: 105 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -86,30 +86,20 @@ public class DynamicModelService {
8686
private static final int MAX_VARCHAR = 65_535;
8787
private static final int ASC_SUFFIX_LEN = 4;
8888
private static final int DESC_SUFFIX_LEN = 5;
89-
private static final String IDENTIFIER_REGEX = "[A-Za-z_][A-Za-z0-9_]*";
90-
private static final String LITERAL_REGEX = "'(?:''|[^'\\r\\n])*'";
91-
private static final String COLUMN_TYPE_REGEX =
92-
"(?:VARCHAR\\([1-9][0-9]{0,4}\\)|INT|TINYINT\\(1\\)|DATE|DATETIME|TEXT|ENUM\\("
93-
+ LITERAL_REGEX
94-
+ "(?:, "
95-
+ LITERAL_REGEX
96-
+ ")*\\))";
97-
private static final String ALTER_REGEX =
98-
"^(?:ADD COLUMN|MODIFY COLUMN) "
99-
+ IDENTIFIER_REGEX
100-
+ " "
101-
+ COLUMN_TYPE_REGEX
102-
+ "(?: NOT NULL)?"
103-
+ "(?: DEFAULT "
104-
+ LITERAL_REGEX
105-
+ ")?"
106-
+ "(?: COMMENT "
107-
+ LITERAL_REGEX
108-
+ ")?"
109-
+ "(?: AFTER "
110-
+ IDENTIFIER_REGEX
111-
+ ")?$";
112-
private static final String DROP_REGEX = "^DROP COLUMN " + IDENTIFIER_REGEX + "$";
89+
90+
private enum AlterOperationType {
91+
ADD,
92+
MODIFY,
93+
DROP
94+
}
95+
96+
private record AlterOperation(
97+
AlterOperationType type,
98+
String columnName,
99+
ParametersDto parameter,
100+
String columnType,
101+
String afterColumn) {
102+
}
113103

114104
private final JdbcTemplate jdbcTemplate;
115105
private final NamedParameterJdbcTemplate namedJdbcTemplate;
@@ -510,7 +500,7 @@ public void modifyTableStructure(Model model) {
510500
col -> col.get("DATA_TYPE")));
511501

512502
// Generate ALTER TABLE statements
513-
List<String> alterStatements = new ArrayList<>();
503+
List<AlterOperation> alterOperations = new ArrayList<>();
514504
// Add or modify columns based on parameters
515505
for (int i = 0; i < parameters.size(); i++) {
516506
String afterColumn = null;
@@ -525,14 +515,22 @@ public void modifyTableStructure(Model model) {
525515

526516
if (!existingColumnMap.containsKey(columnName)) {
527517
// Add new column
528-
String addSql = generateColumnDefinition(param, "add");
529-
if (afterColumn != null) {
530-
addSql += " AFTER " + afterColumn;
531-
}
532-
alterStatements.add(addSql);
518+
alterOperations.add(
519+
new AlterOperation(
520+
AlterOperationType.ADD,
521+
columnName,
522+
param,
523+
null,
524+
afterColumn));
533525
} else if (!existingColumnMap.get(columnName).equalsIgnoreCase(columnType)) {
534526
// Modify existing column
535-
alterStatements.add(String.format("MODIFY COLUMN %s %s", columnName, columnType));
527+
alterOperations.add(
528+
new AlterOperation(
529+
AlterOperationType.MODIFY,
530+
columnName,
531+
null,
532+
columnType,
533+
null));
536534
}
537535
}
538536

@@ -542,29 +540,93 @@ public void modifyTableStructure(Model model) {
542540
for (String existingColumn : existingColumnMap.keySet()) {
543541
SqlIdentifierValidator.validate(existingColumn);
544542
if (parameters.stream().noneMatch(param -> param.getProp().equals(existingColumn))) {
545-
alterStatements.add(String.format("DROP COLUMN %s", existingColumn));
543+
alterOperations.add(
544+
new AlterOperation(
545+
AlterOperationType.DROP,
546+
existingColumn,
547+
null,
548+
null,
549+
null));
546550
}
547551
}
548552

549553
// Execute ALTER TABLE statements
550-
for (String alterStatement : alterStatements) {
551-
executeAlterTableStatement(tableName, alterStatement);
554+
for (AlterOperation operation : alterOperations) {
555+
executeAlterTableStatement(tableName, operation);
552556
}
553557
}
554558

555-
private void executeAlterTableStatement(final String tableName, final String alterStatement) {
556-
if (!tableName.matches("^dynamic_[a-z0-9_]+$")) {
557-
throw new IllegalArgumentException("Invalid dynamic table name");
558-
}
559-
if (alterStatement == null
560-
|| !alterStatement.matches(ALTER_REGEX)
561-
&& !alterStatement.matches(DROP_REGEX)) {
562-
throw new IllegalArgumentException("Invalid ALTER TABLE statement");
559+
private void executeAlterTableStatement(
560+
final String tableName, final AlterOperation operation) {
561+
String safeTable = requireAlterIdentifier(tableName, "tableName");
562+
String sql;
563+
switch (operation.type()) {
564+
case ADD:
565+
sql = buildAddColumnSql(operation, safeTable);
566+
break;
567+
case MODIFY:
568+
sql = buildModifyColumnSql(operation, safeTable);
569+
break;
570+
case DROP:
571+
sql =
572+
"ALTER TABLE "
573+
+ safeTable
574+
+ " DROP COLUMN "
575+
+ requireAlterIdentifier(operation.columnName(), "columnName");
576+
break;
577+
default:
578+
throw new IllegalArgumentException("Unsupported ALTER TABLE operation");
563579
}
564-
final String sql = String.format("ALTER TABLE %s %s", tableName, alterStatement);
565580
jdbcTemplate.execute(sql);
566581
}
567582

583+
private String buildAddColumnSql(
584+
final AlterOperation operation, final String tableName) {
585+
requireAlterIdentifier(operation.columnName(), "columnName");
586+
final String columnDefinition = generateColumnDefinition(operation.parameter(), "add");
587+
final String afterColumn = operation.afterColumn();
588+
return afterColumn == null
589+
? "ALTER TABLE " + tableName + " " + columnDefinition
590+
: "ALTER TABLE "
591+
+ tableName
592+
+ " "
593+
+ columnDefinition
594+
+ " AFTER "
595+
+ requireAlterIdentifier(afterColumn, "afterColumn");
596+
}
597+
598+
private String buildModifyColumnSql(
599+
final AlterOperation operation, final String tableName) {
600+
return "ALTER TABLE "
601+
+ tableName
602+
+ " MODIFY COLUMN "
603+
+ requireAlterIdentifier(operation.columnName(), "columnName")
604+
+ " "
605+
+ requireColumnType(operation.columnType());
606+
}
607+
608+
private String requireAlterIdentifier(final String value, final String name) {
609+
if (value == null || !value.matches("^[A-Za-z_][A-Za-z0-9_]*$")) {
610+
throw new IllegalArgumentException(name + " must be a valid SQL identifier");
611+
}
612+
return value;
613+
}
614+
615+
private String requireColumnType(final String value) {
616+
if (value == null
617+
|| !(value.equals("INT")
618+
|| value.equals("TINYINT")
619+
|| value.equals("DATE")
620+
|| value.equals("TIMESTAMP")
621+
|| value.equals("VARCHAR")
622+
|| value.equals("Enum")
623+
|| value.equals("TEXT")
624+
|| value.matches("^VARCHAR\\([1-9][0-9]{0,4}\\)$"))) {
625+
throw new IllegalArgumentException("Invalid SQL column type");
626+
}
627+
return value;
628+
}
629+
568630
private void addCommonFields(List<ParametersDto> parameters) {
569631
ParametersDto id = new ParametersDto();
570632
id.setProp("id");

0 commit comments

Comments
 (0)