mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 09:40:58 +00:00
[improve] form-urlencode SQL request body in GreptimeSqlQueryExecutor (#4223)
Co-authored-by: Tomsun28 <tomsun28@outlook.com>
This commit is contained in:
+3
-1
@@ -38,6 +38,8 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -79,7 +81,7 @@ public class GreptimeSqlQueryExecutor extends SqlQueryExecutor {
|
|||||||
headers.add(HttpHeaders.AUTHORIZATION, NetworkConstants.BASIC + SignConstants.BLANK + encodedAuth);
|
headers.add(HttpHeaders.AUTHORIZATION, NetworkConstants.BASIC + SignConstants.BLANK + encodedAuth);
|
||||||
}
|
}
|
||||||
|
|
||||||
String requestBody = "sql=" + queryString;
|
String requestBody = "sql=" + URLEncoder.encode(queryString, StandardCharsets.UTF_8);
|
||||||
HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, headers);
|
||||||
|
|
||||||
String url = greptimeProperties.httpEndpoint() + QUERY_PATH;
|
String url = greptimeProperties.httpEndpoint() + QUERY_PATH;
|
||||||
|
|||||||
+36
@@ -20,12 +20,16 @@
|
|||||||
package org.apache.hertzbeat.warehouse.db;
|
package org.apache.hertzbeat.warehouse.db;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -34,6 +38,7 @@ import org.apache.hertzbeat.warehouse.store.history.tsdb.greptime.GreptimeSqlQue
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
@@ -90,6 +95,37 @@ class GreptimeSqlQueryExecutorTest {
|
|||||||
assertEquals(85.5, result.get(0).get("value"));
|
assertEquals(85.5, result.get(0).get("value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void testRequestBodyIsFormEncoded() {
|
||||||
|
when(restTemplate.exchange(
|
||||||
|
any(String.class),
|
||||||
|
eq(HttpMethod.POST),
|
||||||
|
any(HttpEntity.class),
|
||||||
|
eq(GreptimeSqlQueryContent.class)
|
||||||
|
)).thenReturn(new ResponseEntity<>(new GreptimeSqlQueryContent(), HttpStatus.OK));
|
||||||
|
|
||||||
|
// SQL carrying form-urlencoded metacharacters that would pollute the request body
|
||||||
|
// if concatenated raw: '&' would start a second sql= parameter and override the query.
|
||||||
|
String sql = "SELECT * FROM t WHERE name = 'x&sql=DROP TABLE t'";
|
||||||
|
greptimeSqlQueryExecutor.execute(sql);
|
||||||
|
|
||||||
|
ArgumentCaptor<HttpEntity<String>> captor = ArgumentCaptor.forClass(HttpEntity.class);
|
||||||
|
verify(restTemplate).exchange(
|
||||||
|
any(String.class),
|
||||||
|
eq(HttpMethod.POST),
|
||||||
|
captor.capture(),
|
||||||
|
eq(GreptimeSqlQueryContent.class));
|
||||||
|
|
||||||
|
String body = captor.getValue().getBody();
|
||||||
|
assertNotNull(body);
|
||||||
|
// The body must be a single sql= parameter; the '&' inside the SQL must be encoded.
|
||||||
|
String encodedValue = body.substring("sql=".length());
|
||||||
|
assertFalse(encodedValue.contains("&"), "raw '&' in body causes HTTP parameter pollution");
|
||||||
|
// Decoding the value must yield exactly the original SQL, lossless round-trip.
|
||||||
|
assertEquals(sql, URLDecoder.decode(encodedValue, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testExecuteError() {
|
void testExecuteError() {
|
||||||
// Mock error response
|
// Mock error response
|
||||||
|
|||||||
Reference in New Issue
Block a user