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

[SPARK-20393][Webu UI] Strengthen Spark to prevent XSS vulnerabilities #17686

Closed
wants to merge 10 commits into from
Closed

[SPARK-20393][Webu UI] Strengthen Spark to prevent XSS vulnerabilities #17686

wants to merge 10 commits into from

Conversation

n-marion
Copy link
Contributor

What changes were proposed in this pull request?

Add stripXSS and stripXSSMap to Spark Core's UIUtils. Calling these functions at any point that getParameter is called against a HttpServletRequest.

How was this patch tested?

Unit tests, IBM Security AppScan Standard no longer showing vulnerabilities, manual verification of WebUI pages.

Copy link
Member

@srowen srowen left a comment

Choose a reason for hiding this comment

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

This is probably fine, but, is this all the calls to request.getParameter? and how real is the threat vs theoretical? anyone who can access Spark can already run arbitrary code on the cluster.

strippedXSSUrl
}

def stripXSSMap(url: Array[String]): Array[String] = {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure what this method is trying to do but it just returns its argument. Do you just mean url.map(stripXSS)? why Map, why url as names?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I appreciate the feedback. The method returned the array of strings stripped of possible XSS issues. I have used your recommendation in the next commit. Map was changed to Array. url is now requestParameter.

@@ -220,18 +220,20 @@ private[ui] class AllJobsPage(parent: JobsTab) extends WebUIPage("") {
jobTag: String,
jobs: Seq[JobUIData],
killEnabled: Boolean): Seq[Node] = {
val allParameters = request.getParameterMap.asScala.toMap
//stripXSS is called to remove suspicious characters used in XSS attacks
val allParameters = request.getParameterMap.asScala.toMap.mapValues(UIUtils.stripXSSMap(_))
Copy link
Member

Choose a reason for hiding this comment

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

(_) is redundant here

@@ -220,18 +220,20 @@ private[ui] class AllJobsPage(parent: JobsTab) extends WebUIPage("") {
jobTag: String,
jobs: Seq[JobUIData],
killEnabled: Boolean): Seq[Node] = {
val allParameters = request.getParameterMap.asScala.toMap
// stripXSS is called to remove suspicious characters used in XSS attacks
val allParameters = request.getParameterMap.asScala.toMap.mapValues(UIUtils.stripXSSArray(_))
Copy link
Member

Choose a reason for hiding this comment

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

Nit: omit (_)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed.

* https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OTG-INPVAL-001)
*/
def stripXSS(requestParameter: String): String = {
var requestParameterStripped = requestParameter
Copy link
Member

Choose a reason for hiding this comment

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

I think the body is simpler as

if (requestParameter == null) {
  null
} else {
  StringEscapeUtils.escapeHtml4(
    requestParameter.replaceAll("(\r\n|\n|\r|%0D%0A|%0A|%0D|'|%27)", ""))
}

I'm not sure if it will matter for performance but you could pull out the regex as a saved instance variable instead of compiling it each time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Followed your suggestion.

Copy link
Member

@srowen srowen left a comment

Choose a reason for hiding this comment

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

These are all the calls to request.getParameter or similar methods right?


/** Utility functions for generating XML pages with spark content. */
private[spark] object UIUtils extends Logging {
val TABLE_CLASS_NOT_STRIPED = "table table-bordered table-condensed"
val TABLE_CLASS_STRIPED = TABLE_CLASS_NOT_STRIPED + " table-striped"
val TABLE_CLASS_STRIPED_SORTABLE = TABLE_CLASS_STRIPED + " sortable"

val NEWLINE_AND_SINGLE_QUOTE_REGEX = "(\r\n|\n|\r|%0D%0A|%0A|%0D|'|%27)"
Copy link
Member

Choose a reason for hiding this comment

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

This is just a string constant rather than regex (with "...".r). If you're going to do it you can make this faster by reusing the Regex object. (Can these members be private while you're at it?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I intended to make it a regex object; but I did miss the .r; By making these members private are you referring to all of the: TABLE_*?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

replaceAll requires (String, String) so I got a compile error with the regex object.

requestParameter.replaceAll(NEWLINE_AND_SINGLE_QUOTE_REGEX, ""))
}

def stripXSSArray(requestParameter: Array[String]): Array[String] = {
Copy link
Member

Choose a reason for hiding this comment

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

I'm on the fence about whether it's worth including this as you can just write _.map(stripXSS) in the two places it's used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll check this again; I had a problem with _.map(stripXSS) compiling; but maybe I did something wrong with it.

And in regards to all the calls; I checked for any type of getParameter call; and also looked for HttpServletRequest with other types of calls. Doesn't appear to be any I missed.

* https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet and
* https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OTG-INPVAL-001)
*/
def stripXSS(requestParameter: String): String = {
Copy link
Member

Choose a reason for hiding this comment

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

If you would, add a couple brief tests of this to UIUtilsSuite

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll work on some.


/** Utility functions for generating XML pages with spark content. */
private[spark] object UIUtils extends Logging {
val TABLE_CLASS_NOT_STRIPED = "table table-bordered table-condensed"
val TABLE_CLASS_STRIPED = TABLE_CLASS_NOT_STRIPED + " table-striped"
val TABLE_CLASS_STRIPED_SORTABLE = TABLE_CLASS_STRIPED + " sortable"

private val NEWLINE_AND_SINGLE_QUOTE_REGEX = "(\r\n|\n|\r|%0D%0A|%0A|%0D|'|%27)"
Copy link
Member

Choose a reason for hiding this comment

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

I still think it's worth making this a regex object if you're going to bother, but otherwise LGTM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will attempt. Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Regex created. Changed replaceAll string method to replaceAllIn regex method. Added new test case for new line in parameter.

@SparkQA
Copy link

SparkQA commented May 4, 2017

Test build #3688 has finished for PR 17686 at commit 18dbd6f.

  • This patch fails Scala style tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented May 6, 2017

Test build #3694 has finished for PR 17686 at commit 39824a8.

  • This patch fails Scala style tests.
  • This patch does not merge cleanly.
  • This patch adds no public classes.

@srowen
Copy link
Member

srowen commented May 8, 2017

@n-marion looks like still some style issues from the checker

@n-marion
Copy link
Contributor Author

n-marion commented May 8, 2017

Missed the import organization. Just ran it locally. Didn't hit same problem.

@SparkQA
Copy link

SparkQA commented May 9, 2017

Test build #3702 has finished for PR 17686 at commit ef1cc25.

  • This patch fails Scala style tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@n-marion
Copy link
Contributor Author

n-marion commented May 9, 2017

Adjusted test-case to shorten string. Rerunning to verify passing as well as scalastyle pass for tests.

@SparkQA
Copy link

SparkQA commented May 9, 2017

Test build #3704 has finished for PR 17686 at commit 8ed9c76.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@srowen
Copy link
Member

srowen commented May 10, 2017

Merged to master/2.2/2.1

@asfgit asfgit closed this in b512233 May 10, 2017
liyichao pushed a commit to liyichao/spark that referenced this pull request May 24, 2017
## What changes were proposed in this pull request?

Add stripXSS and stripXSSMap to Spark Core's UIUtils. Calling these functions at any point that getParameter is called against a HttpServletRequest.

## How was this patch tested?

Unit tests, IBM Security AppScan Standard no longer showing vulnerabilities, manual verification of WebUI pages.

Author: NICHOLAS T. MARION <nmarion@us.ibm.com>

Closes apache#17686 from n-marion/xss-fix.
asfgit pushed a commit that referenced this pull request May 26, 2017
## What changes were proposed in this pull request?

Add stripXSS and stripXSSMap to Spark Core's UIUtils. Calling these functions at any point that getParameter is called against a HttpServletRequest.

## How was this patch tested?

Unit tests, IBM Security AppScan Standard no longer showing vulnerabilities, manual verification of WebUI pages.

Author: NICHOLAS T. MARION <nmarion@us.ibm.com>

Closes #17686 from n-marion/xss-fix.

(cherry picked from commit b512233)
Signed-off-by: Sean Owen <sowen@cloudera.com>
asfgit pushed a commit that referenced this pull request May 27, 2017
Add stripXSS and stripXSSMap to Spark Core's UIUtils. Calling these functions at any point that getParameter is called against a HttpServletRequest.

Unit tests, IBM Security AppScan Standard no longer showing vulnerabilities, manual verification of WebUI pages.

Author: NICHOLAS T. MARION <nmarion@us.ibm.com>

Closes #17686 from n-marion/xss-fix.

(cherry picked from commit b512233)
Signed-off-by: Sean Owen <sowen@cloudera.com>
ambauma pushed a commit to ambauma/spark that referenced this pull request Oct 19, 2017
Add stripXSS and stripXSSMap to Spark Core's UIUtils. Calling these functions at any point that getParameter is called against a HttpServletRequest.

Unit tests, IBM Security AppScan Standard no longer showing vulnerabilities, manual verification of WebUI pages.

Author: NICHOLAS T. MARION <nmarion@us.ibm.com>

Closes apache#17686 from n-marion/xss-fix.
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.

3 participants