Skip to content
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 @@ -909,19 +909,18 @@ public void setShort(int parameterIndex, short x) throws SQLException {

@Override
public void setString(int parameterIndex, String x) {
// if the sql is an insert statement and the value is not a string literal, add single quotes
// The table model only supports single quotes, the tree model sql both single and double quotes
if ("table".equalsIgnoreCase(getSqlDialect())
|| ((sql.trim().toUpperCase().startsWith("INSERT")
&& !((x.startsWith("'") && x.endsWith("'"))
|| ((x.startsWith("\"") && x.endsWith("\""))
&& "tree".equals(getSqlDialect())))))) {
this.parameters.put(parameterIndex, "'" + x + "'");
if (x == null) {
this.parameters.put(parameterIndex, null);
} else {
this.parameters.put(parameterIndex, x);
this.parameters.put(parameterIndex, "'" + escapeSingleQuotes(x) + "'");
}
}

private String escapeSingleQuotes(String value) {
// Escape single quotes with double single quotes
return value.replace("'", "''");
}

@Override
public void setTime(int parameterIndex, Time x) throws SQLException {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public void oneStringArgument1() throws Exception {
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT status, temperature FROM root.ln.wf01.wt01 WHERE temperature < 'abcde' and time > 2017-11-1 0:13:00",
"SELECT status, temperature FROM root.ln.wf01.wt01 WHERE temperature < '''abcde''' and time > 2017-11-1 0:13:00",
argument.getValue().getStatement());
}

Expand All @@ -217,7 +217,7 @@ public void oneStringArgument2() throws Exception {
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT status, temperature FROM root.ln.wf01.wt01 WHERE temperature < \"abcde\" and time > 2017-11-1 0:13:00",
"SELECT status, temperature FROM root.ln.wf01.wt01 WHERE temperature < '\"abcde\"' and time > 2017-11-1 0:13:00",
argument.getValue().getStatement());
}

Expand All @@ -233,7 +233,7 @@ public void oneStringArgument3() throws Exception {
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT status, temperature FROM root.ln.wf01.wt01", argument.getValue().getStatement());
"SELECT status, 'temperature' FROM root.ln.wf01.wt01", argument.getValue().getStatement());
}

@SuppressWarnings("resource")
Expand Down Expand Up @@ -325,7 +325,7 @@ public void testInsertStatement1() throws Exception {
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"INSERT INTO root.ln.wf01.wt01(time,a,b,c,d,e,f) VALUES(12324,false,123,123234345,123.423,-1323.0,'abc')",
"INSERT INTO root.ln.wf01.wt01(time,a,b,c,d,e,f) VALUES(12324,false,123,123234345,123.423,-1323.0,'''abc''')",
argument.getValue().getStatement());
}

Expand All @@ -351,7 +351,7 @@ public void testInsertStatement2() throws Exception {
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"INSERT INTO root.ln.wf01.wt01(time,a,b,c,d,e,f,g,h) VALUES(2017-11-01T00:13:00,false,123,123234345,123.423,-1323.0,\"abc\",'abc','abc')",
"INSERT INTO root.ln.wf01.wt01(time,a,b,c,d,e,f,g,h) VALUES(2017-11-01T00:13:00,false,123,123234345,123.423,-1323.0,'\"abc\"','abc','''abc''')",
argument.getValue().getStatement());
}

Expand All @@ -374,7 +374,7 @@ public void testInsertStatement3() throws Exception {
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"INSERT INTO root.ln.wf01.wt02(time,a,b,c,d,e,f) VALUES(2020-01-01T10:10:10,false,123,123234345,123.423,-1323.0,\"abc\")",
"INSERT INTO root.ln.wf01.wt02(time,a,b,c,d,e,f) VALUES(2020-01-01T10:10:10,false,123,123234345,123.423,-1323.0,'\"abc\"')",
argument.getValue().getStatement());
}

Expand All @@ -400,4 +400,146 @@ public void testInsertStatement4() throws Exception {
"INSERT INTO root.ln.wf01.wt02(time,a,b,c,d,e,f) VALUES(2020-01-01T10:10:10,false,123,123234345,123.423,-1323.0,'abc')",
argument.getValue().getStatement());
}

// ========== Table Model SQL Injection Prevention Tests ==========

@SuppressWarnings("resource")
@Test
public void testTableModelLoginInjectionWithComment() throws Exception {
// Login interface SQL injection attack 1: Using -- comments to bypass password checks
when(connection.getSqlDialect()).thenReturn("table");
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
IoTDBPreparedStatement ps =
new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
ps.setString(1, "admin' --");
ps.setString(2, "password");
ps.execute();

ArgumentCaptor<TSExecuteStatementReq> argument =
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT * FROM users WHERE username = 'admin'' --' AND password = 'password'",
argument.getValue().getStatement());
}

@SuppressWarnings("resource")
@Test
public void testTableModelLoginInjectionWithORCondition() throws Exception {
// Login interface SQL injection attack 2: Bypassing authentication by using 'OR '1'='1
when(connection.getSqlDialect()).thenReturn("table");
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
IoTDBPreparedStatement ps =
new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
ps.setString(1, "admin");
ps.setString(2, "' OR '1'='1");
ps.execute();

ArgumentCaptor<TSExecuteStatementReq> argument =
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT * FROM users WHERE username = 'admin' AND password = ''' OR ''1''=''1'",
argument.getValue().getStatement());
}

@SuppressWarnings("resource")
@Test
public void testTableModelQueryWithMultipleInjectionVectors() throws Exception {
when(connection.getSqlDialect()).thenReturn("table");
String sql = "SELECT * FROM users WHERE email = ?";
IoTDBPreparedStatement ps =
new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
ps.setString(1, "'; DROP TABLE users;");
ps.execute();

ArgumentCaptor<TSExecuteStatementReq> argument =
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT * FROM users WHERE email = '''; DROP TABLE users;'",
argument.getValue().getStatement());
}

@SuppressWarnings("resource")
@Test
public void testTableModelString1() throws Exception {
when(connection.getSqlDialect()).thenReturn("table");
String sql = "SELECT * FROM users WHERE password = ?";
IoTDBPreparedStatement ps =
new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
ps.setString(1, "a'b");
ps.execute();

ArgumentCaptor<TSExecuteStatementReq> argument =
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals("SELECT * FROM users WHERE password = 'a''b'", argument.getValue().getStatement());
}

@SuppressWarnings("resource")
@Test
public void testTableModelString2() throws Exception {
when(connection.getSqlDialect()).thenReturn("table");
String sql = "SELECT * FROM users WHERE password = ?";
IoTDBPreparedStatement ps =
new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
ps.setString(1, "a\'b");
ps.execute();

ArgumentCaptor<TSExecuteStatementReq> argument =
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals("SELECT * FROM users WHERE password = 'a''b'", argument.getValue().getStatement());
}

@SuppressWarnings("resource")
@Test
public void testTableModelString3() throws Exception {
when(connection.getSqlDialect()).thenReturn("table");
String sql = "SELECT * FROM users WHERE password = ?";
IoTDBPreparedStatement ps =
new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
ps.setString(1, "a\\'b");
ps.execute();

ArgumentCaptor<TSExecuteStatementReq> argument =
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT * FROM users WHERE password = 'a\\''b'", argument.getValue().getStatement());
}

@SuppressWarnings("resource")
@Test
public void testTableModelString4() throws Exception {
when(connection.getSqlDialect()).thenReturn("table");
String sql = "SELECT * FROM users WHERE password = ?";
IoTDBPreparedStatement ps =
new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
ps.setString(1, "a\\\'b");
ps.execute();

ArgumentCaptor<TSExecuteStatementReq> argument =
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals(
"SELECT * FROM users WHERE password = 'a\\''b'", argument.getValue().getStatement());
}

@SuppressWarnings("resource")
@Test
public void testTableModelStringWithNull() throws Exception {
when(connection.getSqlDialect()).thenReturn("table");
String sql = "SELECT * FROM users WHERE email = ?";
IoTDBPreparedStatement ps =
new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
ps.setString(1, null);
ps.execute();

ArgumentCaptor<TSExecuteStatementReq> argument =
ArgumentCaptor.forClass(TSExecuteStatementReq.class);
verify(client).executeStatementV2(argument.capture());
assertEquals("SELECT * FROM users WHERE email = null", argument.getValue().getStatement());
}
}