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

SOLR-14886 : suppress stack traces in query response #1632

Merged

Conversation

igiguere
Copy link
Contributor

@igiguere igiguere commented May 8, 2023

https://issues.apache.org/jira/browse/SOLR-14886

Description

Stack traces are considered a security risk. Please refer to OWASP for a full explanation:

https://owasp.org/Top10/A05_2021-Security_Misconfiguration/

Solution

Add a property "hideStackTrace" to solr.xml. In NodeConfig, the default value is "false", for back-compatibility.

Use the new property in ResponseUtils, to print out, or not, the stack trace.

Adapt code that calls ResponseUtils.

Also check if stack traces should be hidden everywhere the "trace" element is added to a response. (I searched for the string"trace" - with quotes - throughout the Solr code. Hope I got everything.)

Tests

org.apache.solr.servlet.HideStackTraceTest : force an exception into the response, and assert that if hideStackTrace=true, the stack trace is not shown.

Checklist

Please review the following and check all that apply:

  • I have reviewed the guidelines for How to Contribute and my code conforms to the standards described there to the best of my ability.
  • I have created a Jira issue and added the issue ID to my pull request title.
  • I have given Solr maintainers access to contribute to my PR branch. (optional but recommended)
  • I have developed this patch against the main branch.
  • I have run ./gradlew check.
  • I have added tests for my changes.
  • I have added documentation for the Reference Guide

@igiguere igiguere changed the title SOLR_14886 : suppress stack traces in query response SOLR-14886 : suppress stack traces in query response May 8, 2023
Copy link
Contributor

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

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

While I can understand that Solr needs NodeConfig / solr.xml, this feels way more like a simple Java system property situation. We certainly have many of the latter.

Maybe someday we would have a unification in a generic way so that we needn't go through all the NodeConfig plumbing just to have some global flag.

@stillalex
Copy link
Member

@igiguere could you rebase on top of main branch (as suggested on the dev list)?
also what name should I use in the CHANGES.txt entry for the credit?

@igiguere
Copy link
Contributor Author

@stillalex : I'm in CHANGES.txt a couple of times with my full name
Isabelle Giguere

@igiguere
Copy link
Contributor Author

I rebased this branch on the fork's main (up to date with /solr main). There were no changes to push, so I don't know if a build will be triggered.
Hopefully, it will work.

@stillalex
Copy link
Member

I'm not seeing a new build, I think you have to force push the rebase so the build can apply correctly

Copy link
Contributor

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

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

See org.apache.solr.search.json.TestJsonRequestWithEdismaxDefType to see a new breed of tests. Notice the SolrClientTestRule. Notice a ConfigRequest is used to manipulate a configuration instead of creating yet another config file. We have too many such config files; it's a maintenance problem. Feedback on this is welcome!

@stillalex
Copy link
Member

stillalex commented Sep 11, 2023

@dsmiley I am attempting to rewrite the test using thew new EmbeddedSolrServerTestRule but I am falling short.
First it seems to shortcut exceptions in the response via checkForExceptions(rsp); method so there is no opportunity for the stacktrace to be populated in the response, what I see now is just the exception being thrown so cannot verify the hideStackTrace flag does anything.
Second it seems to hardcode the response to the binary response (see BinaryResponseWriter.getParsedResponse), so not sure if this might need to change to support other types, for this test it is needed to serialize the error to verify the trace is not there.
please correct if I am missing something obvious here.

mode datapoints (the test and the stacktrace of the exception, left rule init outside for brevity):

  @Test
  public void testHideStackTrace() throws Exception {
    SolrClient client = solrRule.getSolrClient();
    final var req = new QueryRequest(new SolrQuery("qt", "/withError", "q", "*:*" , "wt", "xml"));
    final var rsp = req.process(client); // throws SolrServerException see below
  }
org.apache.solr.client.solrj.SolrServerException: org.apache.solr.client.solrj.SolrServerException: java.lang.RuntimeException: Stack trace should not be populated.
	at __randomizedtesting.SeedInfo.seed([7E5DC4464AD2FF38:1A02C289B04C1233]:0)
	at org.apache.solr.client.solrj.embedded.EmbeddedSolrServer.request(EmbeddedSolrServer.java:277)
	at org.apache.solr.client.solrj.SolrRequest.process(SolrRequest.java:234)
	at org.apache.solr.client.solrj.SolrRequest.process(SolrRequest.java:249)
	at org.apache.solr.servlet.HideStackTraceTest.testHideStackTrace(HideStackTraceTest.java:75)
Caused by: org.apache.solr.client.solrj.SolrServerException: java.lang.RuntimeException: Stack trace should not be populated.
	at org.apache.solr.client.solrj.embedded.EmbeddedSolrServer.checkForExceptions(EmbeddedSolrServer.java:357)
	at org.apache.solr.client.solrj.embedded.EmbeddedSolrServer.request(EmbeddedSolrServer.java:226)
	... 50 more
Caused by: java.lang.RuntimeException: Stack trace should not be populated.
	at org.apache.solr.servlet.HideStackTraceTest$ErrorComponent.process(HideStackTraceTest.java:110)
	at org.apache.solr.handler.component.SearchHandler.handleRequestBody(SearchHandler.java:442)
	at org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:224)
	at org.apache.solr.core.SolrCore.execute(SolrCore.java:2890)
	at org.apache.solr.client.solrj.embedded.EmbeddedSolrServer.request(EmbeddedSolrServer.java:225)
	... 50 more

@dsmiley
Copy link
Contributor

dsmiley commented Sep 11, 2023

Thanks for trying Alex!
I suppose this test is more sensitive to the serialization, in which case you should probably use SolrJettyTestRule.

EmbeddedSolrServer: Ideally, a test (or more likely the test infrastructure behind the scenes) could pick the response format if it wants, say, XML or JSON instead of the parsed NamedList, such as if assertJQ (JSON path custom thing) or assertQ (XPath). The InputStreamResponseParser may be needed, which is a bit of a special thing (see Find-Usages to see for yourself).

@stillalex stillalex force-pushed the SOLR-14886-Suppress_stack_trace_in_Query_response branch from dc7733e to 80bf80a Compare September 11, 2023 18:31
@stillalex
Copy link
Member

@dsmiley I refactored the test as best I could. please take a look and let me know if more cleanup is needed.
I had to rebase+force push to get crave build running again

@@ -301,6 +301,8 @@ && getZkController().getOverseer() != null

private final AllowListUrlChecker allowListUrlChecker;

private final boolean hideStackTrace;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think a simple global boolean needs to be yet another field on CoreContainer. Even the NodeConfig stuff is overkill for what could be a system property.

If we do keep NodeConfig, we could still do away with this field because the NodeConfig stays around as a field on CoreContainer as cfg.

@@ -28,6 +28,10 @@
public class ResponseUtils {
private ResponseUtils() {}

// System property to use if the Solr core does not exist or solr.hideStackTrace is not
// configured. (i.e.: a lot of unit test).
private static final boolean SYSTEM_HIDE_STACK_TRACES = Boolean.getBoolean("solr.hideStackTrace");
Copy link
Contributor

Choose a reason for hiding this comment

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

This is all we need for internal config IMO.

Comment on lines +23 to +24
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
Copy link
Contributor

Choose a reason for hiding this comment

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

As a project, we'd like to get away from needless use of Apache HttpClient. We can use JDK HttpClient here.

@dsmiley
Copy link
Contributor

dsmiley commented Sep 12, 2023

It's sad to see so much ceremony in NodeConfig :-( -- an issue for another PR.

igiguere and others added 8 commits September 12, 2023 13:32
Add a property "hideStackTrace" to solr.xml.  In NodeConfig, the default
value is "false", for back-compatibility.

Use the new property in ResponseUtils, to print out, or not, the stack
trace.

Adapt code that calls ResponseUtils.

Add documentation.

Add unit test
adapt getTypedErrorInfo to suppress the stack trace
address review comments:

- ensure the stack trace is logged while being hidden from the HTTP
response

- evaluate config setting and system property in a single location

Fix unit test
Address review comment: read the system property "solr.hideStackTrace"
only once.

The system property is used if the Solr core does not exist or
solr.hideStackTrace is not configured. (in a lot of unit test).
Documentation also mentions that Solr can run without configuring any
core (not sure how useful it is then):
https://solr.apache.org/guide/solr/latest/configuration-guide/core-discovery.html

Pass a Boolean instead of the SolrCore object to methods of
ResponseUtils.

Search the whole code base for places where "trace" is added, and check
for "hideStackTrace" before adding the trace.

Refactor the unit test: Using an Http2SolrClient, the test threw the
exception that was supposed to demonstrate the fix!  Use a
CloseableHttpClient, to query Solr from "outside", without SolrJ, and
get the plain XMl response.
Address review comments: use boolean instead of Boolean.  Set the system
property as default in NodeConfig.  Simplify the initialization of the
unit test.

Add a logger in HideStackTraceTest, to avoid failures on task
"validateSourcePatterns", due to logger name and logger pattern

Built and checked locally
- gradlew.bat compileJava compileTestJava test
- gradlew.bat tidy check -x test
address review comment: fix default hideStackTrace
@stillalex stillalex force-pushed the SOLR-14886-Suppress_stack_trace_in_Query_response branch from 422925b to 5b5d907 Compare September 12, 2023 20:33
@stillalex
Copy link
Member

having to rebase + force commit to get crave build unstuck is becoming a real pain

@stillalex stillalex merged commit cf30265 into apache:main Sep 12, 2023
2 checks passed
stillalex pushed a commit that referenced this pull request Sep 12, 2023
Added a property "hideStackTrace" to solr.xml or system property 'solr.hideStackTrace' to not include error stack trace in the response.
---------
Co-authored-by: Christine Poerschke <[email protected]>
Co-authored-by: Alex Deparvu <[email protected]>

(cherry picked from commit cf30265)
@igiguere igiguere deleted the SOLR-14886-Suppress_stack_trace_in_Query_response branch September 25, 2023 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants