Skip to content
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

Filter out invalid URI and HTTP method in the error message of no handler found for a REST request #3459

Merged
Merged
Show file tree
Hide file tree
Changes from 3 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
14 changes: 12 additions & 2 deletions server/src/main/java/org/opensearch/rest/RestController.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
Expand Down Expand Up @@ -447,7 +448,9 @@ private void handleUnsupportedHttpMethod(
msg.append("Incorrect HTTP method for uri [").append(uri);
msg.append("] and method [").append(method).append("]");
} else {
msg.append(exception.getMessage());
// Not using the error message directly from 'exception.getMessage()' to avoid unescaped HTML special characters,
// in case false-positive cross site scripting vulnerability is detected by common security scanners.
msg.append("Unexpected http method");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Super nit-pick (sorry): Unexpected HTTP method (just to make it concise with previous error Incorrect HTTP method phrasing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Haha, that definitely makes the messages neat.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated in the commit c586b5b

}
if (validMethodSet.isEmpty() == false) {
msg.append(", allowed: ").append(validMethodSet);
Expand Down Expand Up @@ -488,7 +491,14 @@ private void handleBadRequest(String uri, RestRequest.Method method, RestChannel
try (XContentBuilder builder = channel.newErrorBuilder()) {
builder.startObject();
{
builder.field("error", "no handler found for uri [" + uri + "] and method [" + method + "]");
try {
// Validate input URI to filter out HTML special characters in the error message,
// in case false-positive cross site scripting vulnerability is detected by common security scanners.
uri = new URI(uri).getPath();
builder.field("error", "no handler found for uri [" + uri + "] and method [" + method + "]");
Copy link
Collaborator

Choose a reason for hiding this comment

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

LGTM, do you want to sanitize method as well?

Copy link
Collaborator Author

@tlfeng tlfeng Jun 1, 2022

Choose a reason for hiding this comment

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

Your review is so quick!
Sure, I can sanitize the error message for the HTTP method, although it may not necessary, since there is no code security scanners have an alarm on that. 😄
I will update the code then.

Note:
After taking a look at the code, the error message of invalid HTTP method is directly obtained from the
https://github.com/opensearch-project/OpenSearch/blob/2.0.0/server/src/main/java/org/opensearch/rest/RestController.java#L450
https://github.com/opensearch-project/OpenSearch/blob/2.0.0/modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java#L148

Copy link
Collaborator Author

@tlfeng tlfeng Jun 1, 2022

Choose a reason for hiding this comment

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

Updated in the new commit 863e272 . 👍

} catch (Exception e) {
builder.field("error", "invalid uri has been requested");
}
}
builder.endObject();
channel.sendResponse(new BytesRestResponse(BAD_REQUEST, builder));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,15 @@ public void testFaviconWithWrongHttpMethod() {
assertThat(channel.getRestResponse().getHeaders().get("Allow"), hasItem(equalTo(RestRequest.Method.GET.toString())));
}

public void testHandleBadRequestWithHtmlSpecialCharsInUri() {
final FakeRestRequest fakeRestRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY).withPath(
"/<script>alert('xss');alert(\"&#x6A&#x61&#x76&#x61\");</script>"
).build();
final AssertingChannel channel = new AssertingChannel(fakeRestRequest, true, RestStatus.BAD_REQUEST);
restController.dispatchRequest(fakeRestRequest, channel, client.threadPool().getThreadContext());
assertThat(channel.getRestResponse().content().utf8ToString(), containsString("invalid uri has been requested"));
}

public void testDispatchUnsupportedHttpMethod() {
final boolean hasContent = randomBoolean();
final RestRequest request = RestRequest.request(xContentRegistry(), new HttpRequest() {
Expand Down Expand Up @@ -623,6 +632,7 @@ public Exception getInboundException() {
assertTrue(channel.getSendResponseCalled());
assertThat(channel.getRestResponse().getHeaders().containsKey("Allow"), equalTo(true));
assertThat(channel.getRestResponse().getHeaders().get("Allow"), hasItem(equalTo(RestRequest.Method.GET.toString())));
assertThat(channel.getRestResponse().content().utf8ToString(), containsString("Unexpected http method"));
Copy link
Collaborator

@reta reta Jun 1, 2022

Choose a reason for hiding this comment

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

I think this case case throws an exception when getHttpMethod() is requested, could you please add a test case with HTTP method like "<script>alert('xss');alert(\"&#x6A&#x61&#x76&#x61\");</script>" to make sure it won't sneak in? Thank you.

Copy link
Collaborator Author

@tlfeng tlfeng Jun 1, 2022

Choose a reason for hiding this comment

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

Looks like this test case shows the result of any unsupported HTTP method, since the handler for HTTP method will always throw an exception https://github.com/opensearch-project/OpenSearch/blob/2.0.0/server/src/test/java/org/opensearch/rest/RestControllerTests.java#L560.
I will add a separate test for it, to use the real scenario.

Copy link
Collaborator Author

@tlfeng tlfeng Jun 2, 2022

Choose a reason for hiding this comment

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

@reta Sorry I find it very hard to simulate the real process after receiving an specific wrong HTTP method in the unit test.
The HTTP method that used to build RestRequest comes from interface HttpRequest, and it has to be an item of the enum. I couldn't find an existing class that implements interface HttpRequest can accept arbitrary HTTP method, and can be used in the test class.
In real scenario, using any HTTP method other than those listed in the enum will get an exception, and the current code directly throws an exception, so I think the current unit test is likely enough.
To make the assertion more effective, I changed to use equalTo instead of containString to validate the error message, in the new commit 3a7a484

Copy link
Collaborator

Choose a reason for hiding this comment

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

Got it, sorry about that @tlfeng , thank you!

Copy link
Collaborator Author

@tlfeng tlfeng Jun 2, 2022

Choose a reason for hiding this comment

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

Never mind at all 😁. Thanks for your opinion.

}

private static final class TestHttpServerTransport extends AbstractLifecycleComponent implements HttpServerTransport {
Expand Down