Skip to content

Conversation

@Young-Leo
Copy link
Contributor

Support the JDBC client to prevent SQL injection

Comment on lines 919 to 921
// Escape single quotes to prevent SQL injection: ' -> \'
String escapedValue = escapeString(x);
this.parameters.put(parameterIndex, "'" + escapedValue + "'");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in tree model, constant string can use both ' and "

return null;
}
// Escape single quotes to prevent SQL injection
return value.replace("'", "\\'");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return value.replace("'", "\\'");
return value.replace("'", "''");

using '' to be the escaper?

@JackieTien97 JackieTien97 requested a review from Copilot November 12, 2025 02:34
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request attempts to add SQL injection prevention to the IoTDB JDBC client by implementing string escaping in prepared statements. However, the implementation contains a critical security flaw: it uses backslash escaping ('\') instead of the SQL-standard quote doubling (''') that IoTDB's SQL grammar actually requires.

Key Changes:

  • Added escapeString() method to escape single quotes in string parameters
  • Applied escaping to string parameters in table model and INSERT statements
  • Added 8 test cases covering various SQL injection attack vectors and edge cases

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 14 comments.

File Description
iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java Implements escaping logic with incorrect backslash-based method instead of SQL-standard quote doubling
iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java Adds comprehensive SQL injection prevention tests, but all assertions expect incorrect backslash escaping instead of quote doubling

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT * FROM users WHERE username = 'admin\\' --' AND password = 'password'",
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected escaped string is incorrect. According to IoTDB's SQL grammar, single quotes should be escaped by doubling them (''), not with backslashes (\').

The expected output should be:

"SELECT * FROM users WHERE username = 'admin'' --' AND password = 'password'"

Note: admin' -- becomes admin'' -- (the single quote is doubled), not admin\' --.

Suggested change
"SELECT * FROM users WHERE username = 'admin\\' --' AND password = 'password'",
"SELECT * FROM users WHERE username = 'admin'' --' AND password = 'password'",

Copilot uses AI. Check for mistakes.
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT * FROM users WHERE username = 'admin' AND password = '\\' OR \\'1\\'=\\'1'",
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected escaped string is incorrect. According to IoTDB's SQL grammar, single quotes should be escaped by doubling them (''), not with backslashes (\').

The expected output should be:

"SELECT * FROM users WHERE username = 'admin' AND password = ''' OR ''1''=''1'"

Each single quote in ' OR '1'='1 should be doubled: '' OR ''1''=''1.

Suggested change
"SELECT * FROM users WHERE username = 'admin' AND password = '\\' OR \\'1\\'=\\'1'",
"SELECT * FROM users WHERE username = 'admin' AND password = ''' OR ''1''=''1'",

Copilot uses AI. Check for mistakes.
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT * FROM users WHERE email = '\\'; DROP TABLE users;'",
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected escaped string is incorrect. According to IoTDB's SQL grammar, single quotes should be escaped by doubling them (''), not with backslashes (\').

The expected output should be:

"SELECT * FROM users WHERE email = '''; DROP TABLE users;'"

The initial single quote in '; DROP TABLE users; should be doubled: ''.

Suggested change
"SELECT * FROM users WHERE email = '\\'; DROP TABLE users;'",
"SELECT * FROM users WHERE email = '''; DROP TABLE users;'",

Copilot uses AI. Check for mistakes.
// a\\'b(Java literal) -> a\'b(actual string) -> a\\'b(escaped) -> a\\\\'b(Java literal in final
// SQL statement)
assertEquals(
"SELECT * FROM users WHERE password = 'a\\\\'b'", argument.getValue().getStatement());
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected escaped string is incorrect. According to IoTDB's SQL grammar, single quotes should be escaped by doubling them (''), not with backslashes (\').

The expected output should be:

"SELECT * FROM users WHERE password = 'a\\''b'"

Note: a\\'b as a Java string literal represents the actual string a\'b (containing a backslash and a quote). Only the single quote should be doubled, so it becomes a\''b (backslash, two single quotes, b), which in Java string literal form is 'a\\''b'.

Suggested change
"SELECT * FROM users WHERE password = 'a\\\\'b'", argument.getValue().getStatement());
"SELECT * FROM users WHERE password = 'a\\''b'", argument.getValue().getStatement());

Copilot uses AI. Check for mistakes.
Comment on lines 927 to 942
/**
* Escapes single quotes in a string to prevent SQL injection. Replaces each single quote (') with
* a backslash-escaped single quote (\').
*
* <p>Note: The backslash in a Java string must be escaped, while the single quote in a Java
* string can be escaped or not.
*
* <ul>
* <li>Input "O'Reilly" becomes "O\'Reilly" (correctly escaped)
* <li>Input "a\'b" (Java string literal, actual content is a'b) becomes "a\'b"
* <li>Input "a\\'b" (Java string literal, actual content is a\'b) becomes "a\\'b"
* </ul>
*
* @param value the string to escape
* @return the escaped string
*/
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation describes an incorrect escaping mechanism. According to IoTDB's SQL grammar (RelationalSql.g4), single quotes should be escaped by doubling them (' -> ''), not with backslashes.

The documentation should be updated to reflect the correct SQL-standard escaping:

/**
 * Escapes single quotes in a string to prevent SQL injection. Replaces each single quote (') with
 * two consecutive single quotes ('').
 *
 * <p>This follows SQL standards where single quotes within string literals are escaped by doubling them.
 *
 * <ul>
 *   <li>Input "O'Reilly" becomes "O''Reilly"
 *   <li>Input "a'b" becomes "a''b"
 *   <li>Input "admin' --" becomes "admin'' --"
 * </ul>
 *
 * @param value the string to escape
 * @return the escaped string
 */

Copilot uses AI. Check for mistakes.
// a'b(Java literal) -> a'b(actual string) -> a\'b(escaped) -> a\\'b(Java literal in final SQL
// statement)
assertEquals(
"SELECT * FROM users WHERE password = 'a\\'b'", argument.getValue().getStatement());
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected escaped string is incorrect. According to IoTDB's SQL grammar, single quotes should be escaped by doubling them (''), not with backslashes (\').

The expected output should be:

"SELECT * FROM users WHERE password = 'a''b'"

The single quote in a'b should be doubled to become a''b.

Suggested change
"SELECT * FROM users WHERE password = 'a\\'b'", argument.getValue().getStatement());
"SELECT * FROM users WHERE password = 'a''b'", argument.getValue().getStatement());

Copilot uses AI. Check for mistakes.
// a\'b(Java literal) -> a'b(actual string) -> a\'b(escaped) -> a\\'b(Java literal in final SQL
// statement)
assertEquals(
"SELECT * FROM users WHERE password = 'a\\'b'", argument.getValue().getStatement());
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected escaped string is incorrect. According to IoTDB's SQL grammar, single quotes should be escaped by doubling them (''), not with backslashes (\').

The expected output should be:

"SELECT * FROM users WHERE password = 'a''b'"

Note: a\'b as a Java string literal represents the actual string a'b (the backslash escapes the quote in Java source code only). This should be escaped to a''b in SQL.

Copilot uses AI. Check for mistakes.
// final
// SQL statement)
assertEquals(
"SELECT * FROM users WHERE password = 'a\\\\'b'", argument.getValue().getStatement());
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected escaped string is incorrect. According to IoTDB's SQL grammar, single quotes should be escaped by doubling them (''), not with backslashes (\').

The expected output should be:

"SELECT * FROM users WHERE password = 'a\\''b'"

Note: Both a\\'b and a\\\'b as Java string literals represent the same actual string a\'b (containing a backslash and a quote). Only the single quote should be doubled, so it becomes a\''b (backslash, two single quotes, b), which in Java string literal form is 'a\\''b'.

Suggested change
"SELECT * FROM users WHERE password = 'a\\\\'b'", argument.getValue().getStatement());
"SELECT * FROM users WHERE password = 'a\\''b'", argument.getValue().getStatement());

Copilot uses AI. Check for mistakes.
Comment on lines 515 to 516
// a\\'b(Java literal) -> a\'b(actual string) -> a\\'b(escaped) -> a\\\\'b(Java literal in final
// SQL statement)
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment describes an incorrect transformation. With the correct SQL-standard escaping, the transformation should be:

// a\\'b(Java literal) -> a\'b(actual string) -> a\''b(escaped) -> 'a\\''b'(Java literal in final SQL statement)

Only the single quote should be doubled. The backslash character should remain as-is.

Copilot uses AI. Check for mistakes.
Comment on lines 534 to 536
// a\\\'b(Java literal) -> a\'b(actual string) -> a\\'b(escaped) -> a\\\\'b(Java literal in
// final
// SQL statement)
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment describes an incorrect transformation. With the correct SQL-standard escaping, the transformation should be:

// a\\\'b(Java literal) -> a\'b(actual string) -> a\''b(escaped) -> 'a\\''b'(Java literal in final SQL statement)

Only the single quote should be doubled. The backslash character should remain as-is.

Suggested change
// a\\\'b(Java literal) -> a\'b(actual string) -> a\\'b(escaped) -> a\\\\'b(Java literal in
// final
// SQL statement)
// a\\\'b(Java literal) -> a\'b(actual string) -> a\''b(escaped) -> 'a\\''b'(Java literal in final SQL statement)

Copilot uses AI. Check for mistakes.
@JackieTien97 JackieTien97 merged commit 96e8681 into apache:master Nov 12, 2025
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants