-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Support the JDBC client to prevent SQL injection #16734
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
Support the JDBC client to prevent SQL injection #16734
Conversation
| // Escape single quotes to prevent SQL injection: ' -> \' | ||
| String escapedValue = escapeString(x); | ||
| this.parameters.put(parameterIndex, "'" + escapedValue + "'"); |
There was a problem hiding this comment.
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("'", "\\'"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return value.replace("'", "\\'"); | |
| return value.replace("'", "''"); |
using '' to be the escaper?
There was a problem hiding this 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'", |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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\' --.
| "SELECT * FROM users WHERE username = 'admin\\' --' AND password = 'password'", | |
| "SELECT * FROM users WHERE username = 'admin'' --' AND password = 'password'", |
| ArgumentCaptor.forClass(TSExecuteStatementReq.class); | ||
| verify(client).executeStatementV2(argument.capture()); | ||
| assertEquals( | ||
| "SELECT * FROM users WHERE username = 'admin' AND password = '\\' OR \\'1\\'=\\'1'", |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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.
| "SELECT * FROM users WHERE username = 'admin' AND password = '\\' OR \\'1\\'=\\'1'", | |
| "SELECT * FROM users WHERE username = 'admin' AND password = ''' OR ''1''=''1'", |
| ArgumentCaptor.forClass(TSExecuteStatementReq.class); | ||
| verify(client).executeStatementV2(argument.capture()); | ||
| assertEquals( | ||
| "SELECT * FROM users WHERE email = '\\'; DROP TABLE users;'", |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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: ''.
| "SELECT * FROM users WHERE email = '\\'; DROP TABLE users;'", | |
| "SELECT * FROM users WHERE email = '''; DROP TABLE users;'", |
| // 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()); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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'.
| "SELECT * FROM users WHERE password = 'a\\\\'b'", argument.getValue().getStatement()); | |
| "SELECT * FROM users WHERE password = 'a\\''b'", argument.getValue().getStatement()); |
| /** | ||
| * 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 | ||
| */ |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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
*/| // 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()); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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.
| "SELECT * FROM users WHERE password = 'a\\'b'", argument.getValue().getStatement()); | |
| "SELECT * FROM users WHERE password = 'a''b'", argument.getValue().getStatement()); |
| // 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()); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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.
| // final | ||
| // SQL statement) | ||
| assertEquals( | ||
| "SELECT * FROM users WHERE password = 'a\\\\'b'", argument.getValue().getStatement()); |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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'.
| "SELECT * FROM users WHERE password = 'a\\\\'b'", argument.getValue().getStatement()); | |
| "SELECT * FROM users WHERE password = 'a\\''b'", argument.getValue().getStatement()); |
| // a\\'b(Java literal) -> a\'b(actual string) -> a\\'b(escaped) -> a\\\\'b(Java literal in final | ||
| // SQL statement) |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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.
| // a\\\'b(Java literal) -> a\'b(actual string) -> a\\'b(escaped) -> a\\\\'b(Java literal in | ||
| // final | ||
| // SQL statement) |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
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.
| // 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) |
Support the JDBC client to prevent SQL injection