-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathQueryParamSmugglingTest.java
More file actions
58 lines (51 loc) · 2.35 KB
/
Copy pathQueryParamSmugglingTest.java
File metadata and controls
58 lines (51 loc) · 2.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.retailsvc.http;
import static java.net.http.HttpRequest.BodyPublishers.noBody;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import com.retailsvc.http.spec.Spec;
import java.io.InputStream;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
class QueryParamSmugglingTest extends ServerBaseTest {
@Test
void encodedAmpersandCannotSmuggleAValuePastQueryValidation() throws Exception {
// Constrain q1 so any value containing '&' or '=' fails validation.
constrainQ1ToLowercaseLetters();
server = newServer(Map.of());
// %26 must stay inside q1: the handler would decode q1 to "abc&x=y", so validation must see the
// same value and reject it against ^[a-z]+$ (400). The exploit was that validation parsed the
// already-decoded query and saw q1="abc" (passing) while the handler received "abc&x=y".
var request = newRequest(server, "/params/query?q1=abc%26x=y&q2=ok", "GET", noBody());
HttpResponse<String> response = httpClient().send(request, BodyHandlers.ofString());
assertThat(response.statusCode()).isEqualTo(400);
}
@SuppressWarnings("unchecked")
private void constrainQ1ToLowercaseLetters() {
spec =
assertDoesNotThrow(
() -> {
try (InputStream in =
QueryParamSmugglingTest.class.getResourceAsStream("/openapi.json")) {
Map<String, Object> raw =
(Map<String, Object>)
gson.fromJson(
new String(in.readAllBytes(), StandardCharsets.UTF_8), Map.class);
var paths = (Map<String, Object>) raw.get("paths");
var op =
(Map<String, Object>)
((Map<String, Object>) paths.get("/params/query")).get("get");
for (Object p : (List<Object>) op.get("parameters")) {
var param = (Map<String, Object>) p;
if ("q1".equals(param.get("name"))) {
((Map<String, Object>) param.get("schema")).put("pattern", "^[a-z]+$");
}
}
return Spec.from(raw);
}
});
}
}