Skip to content

Commit 38f37c5

Browse files
n-marionsrowen
authored andcommitted
[SPARK-20393][WEBU UI] Strengthen Spark to prevent XSS vulnerabilities
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>
1 parent ebd72f4 commit 38f37c5

File tree

19 files changed

+140
-54
lines changed

19 files changed

+140
-54
lines changed

core/src/main/scala/org/apache/spark/deploy/history/HistoryPage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ import org.apache.spark.ui.{UIUtils, WebUIPage}
2626
private[history] class HistoryPage(parent: HistoryServer) extends WebUIPage("") {
2727

2828
def render(request: HttpServletRequest): Seq[Node] = {
29+
// stripXSS is called first to remove suspicious characters used in XSS attacks
2930
val requestedIncomplete =
30-
Option(request.getParameter("showIncomplete")).getOrElse("false").toBoolean
31+
Option(UIUtils.stripXSS(request.getParameter("showIncomplete"))).getOrElse("false").toBoolean
3132

3233
val allAppsSize = parent.getApplicationList().count(_.completed != requestedIncomplete)
3334
val eventLogsUnderProcessCount = parent.getEventLogsUnderProcess()

core/src/main/scala/org/apache/spark/deploy/master/ui/ApplicationPage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ private[ui] class ApplicationPage(parent: MasterWebUI) extends WebUIPage("app")
3333

3434
/** Executor details for a particular application */
3535
def render(request: HttpServletRequest): Seq[Node] = {
36-
val appId = request.getParameter("appId")
36+
// stripXSS is called first to remove suspicious characters used in XSS attacks
37+
val appId = UIUtils.stripXSS(request.getParameter("appId"))
3738
val state = master.askWithRetry[MasterStateResponse](RequestMasterState)
3839
val app = state.activeApps.find(_.id == appId)
3940
.getOrElse(state.completedApps.find(_.id == appId).orNull)

core/src/main/scala/org/apache/spark/deploy/master/ui/MasterPage.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ private[ui] class MasterPage(parent: MasterWebUI) extends WebUIPage("") {
5757
private def handleKillRequest(request: HttpServletRequest, action: String => Unit): Unit = {
5858
if (parent.killEnabled &&
5959
parent.master.securityMgr.checkModifyPermissions(request.getRemoteUser)) {
60-
val killFlag = Option(request.getParameter("terminate")).getOrElse("false").toBoolean
61-
val id = Option(request.getParameter("id"))
60+
// stripXSS is called first to remove suspicious characters used in XSS attacks
61+
val killFlag =
62+
Option(UIUtils.stripXSS(request.getParameter("terminate"))).getOrElse("false").toBoolean
63+
val id = Option(UIUtils.stripXSS(request.getParameter("id")))
6264
if (id.isDefined && killFlag) {
6365
action(id.get)
6466
}

core/src/main/scala/org/apache/spark/deploy/worker/ui/LogPage.scala

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ private[ui] class LogPage(parent: WorkerWebUI) extends WebUIPage("logPage") with
3535
private val supportedLogTypes = Set("stderr", "stdout")
3636
private val defaultBytes = 100 * 1024
3737

38+
// stripXSS is called first to remove suspicious characters used in XSS attacks
3839
def renderLog(request: HttpServletRequest): String = {
39-
val appId = Option(request.getParameter("appId"))
40-
val executorId = Option(request.getParameter("executorId"))
41-
val driverId = Option(request.getParameter("driverId"))
42-
val logType = request.getParameter("logType")
43-
val offset = Option(request.getParameter("offset")).map(_.toLong)
44-
val byteLength = Option(request.getParameter("byteLength")).map(_.toInt).getOrElse(defaultBytes)
40+
val appId = Option(UIUtils.stripXSS(request.getParameter("appId")))
41+
val executorId = Option(UIUtils.stripXSS(request.getParameter("executorId")))
42+
val driverId = Option(UIUtils.stripXSS(request.getParameter("driverId")))
43+
val logType = UIUtils.stripXSS(request.getParameter("logType"))
44+
val offset = Option(UIUtils.stripXSS(request.getParameter("offset"))).map(_.toLong)
45+
val byteLength =
46+
Option(UIUtils.stripXSS(request.getParameter("byteLength"))).map(_.toInt)
47+
.getOrElse(defaultBytes)
4548

4649
val logDir = (appId, executorId, driverId) match {
4750
case (Some(a), Some(e), None) =>
@@ -57,13 +60,16 @@ private[ui] class LogPage(parent: WorkerWebUI) extends WebUIPage("logPage") with
5760
pre + logText
5861
}
5962

63+
// stripXSS is called first to remove suspicious characters used in XSS attacks
6064
def render(request: HttpServletRequest): Seq[Node] = {
61-
val appId = Option(request.getParameter("appId"))
62-
val executorId = Option(request.getParameter("executorId"))
63-
val driverId = Option(request.getParameter("driverId"))
64-
val logType = request.getParameter("logType")
65-
val offset = Option(request.getParameter("offset")).map(_.toLong)
66-
val byteLength = Option(request.getParameter("byteLength")).map(_.toInt).getOrElse(defaultBytes)
65+
val appId = Option(UIUtils.stripXSS(request.getParameter("appId")))
66+
val executorId = Option(UIUtils.stripXSS(request.getParameter("executorId")))
67+
val driverId = Option(UIUtils.stripXSS(request.getParameter("driverId")))
68+
val logType = UIUtils.stripXSS(request.getParameter("logType"))
69+
val offset = Option(UIUtils.stripXSS(request.getParameter("offset"))).map(_.toLong)
70+
val byteLength =
71+
Option(UIUtils.stripXSS(request.getParameter("byteLength"))).map(_.toInt)
72+
.getOrElse(defaultBytes)
6773

6874
val (logDir, params, pageName) = (appId, executorId, driverId) match {
6975
case (Some(a), Some(e), None) =>

core/src/main/scala/org/apache/spark/ui/UIUtils.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import scala.util.control.NonFatal
2525
import scala.xml._
2626
import scala.xml.transform.{RewriteRule, RuleTransformer}
2727

28+
import org.apache.commons.lang3.StringEscapeUtils
29+
2830
import org.apache.spark.internal.Logging
2931
import org.apache.spark.ui.scope.RDDOperationGraph
3032

@@ -34,6 +36,8 @@ private[spark] object UIUtils extends Logging {
3436
val TABLE_CLASS_STRIPED = TABLE_CLASS_NOT_STRIPED + " table-striped"
3537
val TABLE_CLASS_STRIPED_SORTABLE = TABLE_CLASS_STRIPED + " sortable"
3638

39+
private val NEWLINE_AND_SINGLE_QUOTE_REGEX = raw"(?i)(\r\n|\n|\r|%0D%0A|%0A|%0D|'|%27)".r
40+
3741
// SimpleDateFormat is not thread-safe. Don't expose it to avoid improper use.
3842
private val dateFormat = new ThreadLocal[SimpleDateFormat]() {
3943
override def initialValue(): SimpleDateFormat =
@@ -524,4 +528,21 @@ private[spark] object UIUtils extends Logging {
524528
origHref
525529
}
526530
}
531+
532+
/**
533+
* Remove suspicious characters of user input to prevent Cross-Site scripting (XSS) attacks
534+
*
535+
* For more information about XSS testing:
536+
* https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet and
537+
* https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OTG-INPVAL-001)
538+
*/
539+
def stripXSS(requestParameter: String): String = {
540+
if (requestParameter == null) {
541+
null
542+
} else {
543+
// Remove new lines and single quotes, followed by escaping HTML version 4.0
544+
StringEscapeUtils.escapeHtml4(
545+
NEWLINE_AND_SINGLE_QUOTE_REGEX.replaceAllIn(requestParameter, ""))
546+
}
547+
}
527548
}

core/src/main/scala/org/apache/spark/ui/exec/ExecutorThreadDumpPage.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ private[ui] class ExecutorThreadDumpPage(parent: ExecutorsTab) extends WebUIPage
2727

2828
private val sc = parent.sc
2929

30+
// stripXSS is called first to remove suspicious characters used in XSS attacks
3031
def render(request: HttpServletRequest): Seq[Node] = {
31-
val executorId = Option(request.getParameter("executorId")).map { executorId =>
32+
val executorId =
33+
Option(UIUtils.stripXSS(request.getParameter("executorId"))).map { executorId =>
3234
UIUtils.decodeURLParameter(executorId)
3335
}.getOrElse {
3436
throw new IllegalArgumentException(s"Missing executorId parameter")

core/src/main/scala/org/apache/spark/ui/jobs/AllJobsPage.scala

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,18 +220,20 @@ private[ui] class AllJobsPage(parent: JobsTab) extends WebUIPage("") {
220220
jobTag: String,
221221
jobs: Seq[JobUIData],
222222
killEnabled: Boolean): Seq[Node] = {
223-
val allParameters = request.getParameterMap.asScala.toMap
223+
// stripXSS is called to remove suspicious characters used in XSS attacks
224+
val allParameters = request.getParameterMap.asScala.toMap.mapValues(_.map(UIUtils.stripXSS))
224225
val parameterOtherTable = allParameters.filterNot(_._1.startsWith(jobTag))
225226
.map(para => para._1 + "=" + para._2(0))
226227

227228
val someJobHasJobGroup = jobs.exists(_.jobGroup.isDefined)
228229
val jobIdTitle = if (someJobHasJobGroup) "Job Id (Job Group)" else "Job Id"
229230

230-
val parameterJobPage = request.getParameter(jobTag + ".page")
231-
val parameterJobSortColumn = request.getParameter(jobTag + ".sort")
232-
val parameterJobSortDesc = request.getParameter(jobTag + ".desc")
233-
val parameterJobPageSize = request.getParameter(jobTag + ".pageSize")
234-
val parameterJobPrevPageSize = request.getParameter(jobTag + ".prevPageSize")
231+
// stripXSS is called first to remove suspicious characters used in XSS attacks
232+
val parameterJobPage = UIUtils.stripXSS(request.getParameter(jobTag + ".page"))
233+
val parameterJobSortColumn = UIUtils.stripXSS(request.getParameter(jobTag + ".sort"))
234+
val parameterJobSortDesc = UIUtils.stripXSS(request.getParameter(jobTag + ".desc"))
235+
val parameterJobPageSize = UIUtils.stripXSS(request.getParameter(jobTag + ".pageSize"))
236+
val parameterJobPrevPageSize = UIUtils.stripXSS(request.getParameter(jobTag + ".prevPageSize"))
235237

236238
val jobPage = Option(parameterJobPage).map(_.toInt).getOrElse(1)
237239
val jobSortColumn = Option(parameterJobSortColumn).map { sortColumn =>

core/src/main/scala/org/apache/spark/ui/jobs/JobPage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ private[ui] class JobPage(parent: JobsTab) extends WebUIPage("job") {
187187
val listener = parent.jobProgresslistener
188188

189189
listener.synchronized {
190-
val parameterId = request.getParameter("id")
190+
// stripXSS is called first to remove suspicious characters used in XSS attacks
191+
val parameterId = UIUtils.stripXSS(request.getParameter("id"))
191192
require(parameterId != null && parameterId.nonEmpty, "Missing id parameter")
192193

193194
val jobId = parameterId.toInt

core/src/main/scala/org/apache/spark/ui/jobs/JobsTab.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ package org.apache.spark.ui.jobs
2020
import javax.servlet.http.HttpServletRequest
2121

2222
import org.apache.spark.scheduler.SchedulingMode
23-
import org.apache.spark.ui.{SparkUI, SparkUITab}
23+
import org.apache.spark.ui.{SparkUI, SparkUITab, UIUtils}
2424

2525
/** Web UI showing progress status of all jobs in the given SparkContext. */
2626
private[ui] class JobsTab(parent: SparkUI) extends SparkUITab(parent, "jobs") {
@@ -40,7 +40,8 @@ private[ui] class JobsTab(parent: SparkUI) extends SparkUITab(parent, "jobs") {
4040

4141
def handleKillRequest(request: HttpServletRequest): Unit = {
4242
if (killEnabled && parent.securityManager.checkModifyPermissions(request.getRemoteUser)) {
43-
val jobId = Option(request.getParameter("id")).map(_.toInt)
43+
// stripXSS is called first to remove suspicious characters used in XSS attacks
44+
val jobId = Option(UIUtils.stripXSS(request.getParameter("id"))).map(_.toInt)
4445
jobId.foreach { id =>
4546
if (jobProgresslistener.activeJobs.contains(id)) {
4647
sc.foreach(_.cancelJob(id))

core/src/main/scala/org/apache/spark/ui/jobs/PoolPage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ private[ui] class PoolPage(parent: StagesTab) extends WebUIPage("pool") {
3131

3232
def render(request: HttpServletRequest): Seq[Node] = {
3333
listener.synchronized {
34-
val poolName = Option(request.getParameter("poolname")).map { poolname =>
34+
// stripXSS is called first to remove suspicious characters used in XSS attacks
35+
val poolName = Option(UIUtils.stripXSS(request.getParameter("poolname"))).map { poolname =>
3536
UIUtils.decodeURLParameter(poolname)
3637
}.getOrElse {
3738
throw new IllegalArgumentException(s"Missing poolname parameter")

core/src/main/scala/org/apache/spark/ui/jobs/StagePage.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,18 @@ private[ui] class StagePage(parent: StagesTab) extends WebUIPage("stage") {
8787

8888
def render(request: HttpServletRequest): Seq[Node] = {
8989
progressListener.synchronized {
90-
val parameterId = request.getParameter("id")
90+
// stripXSS is called first to remove suspicious characters used in XSS attacks
91+
val parameterId = UIUtils.stripXSS(request.getParameter("id"))
9192
require(parameterId != null && parameterId.nonEmpty, "Missing id parameter")
9293

93-
val parameterAttempt = request.getParameter("attempt")
94+
val parameterAttempt = UIUtils.stripXSS(request.getParameter("attempt"))
9495
require(parameterAttempt != null && parameterAttempt.nonEmpty, "Missing attempt parameter")
9596

96-
val parameterTaskPage = request.getParameter("task.page")
97-
val parameterTaskSortColumn = request.getParameter("task.sort")
98-
val parameterTaskSortDesc = request.getParameter("task.desc")
99-
val parameterTaskPageSize = request.getParameter("task.pageSize")
100-
val parameterTaskPrevPageSize = request.getParameter("task.prevPageSize")
97+
val parameterTaskPage = UIUtils.stripXSS(request.getParameter("task.page"))
98+
val parameterTaskSortColumn = UIUtils.stripXSS(request.getParameter("task.sort"))
99+
val parameterTaskSortDesc = UIUtils.stripXSS(request.getParameter("task.desc"))
100+
val parameterTaskPageSize = UIUtils.stripXSS(request.getParameter("task.pageSize"))
101+
val parameterTaskPrevPageSize = UIUtils.stripXSS(request.getParameter("task.prevPageSize"))
101102

102103
val taskPage = Option(parameterTaskPage).map(_.toInt).getOrElse(1)
103104
val taskSortColumn = Option(parameterTaskSortColumn).map { sortColumn =>

core/src/main/scala/org/apache/spark/ui/jobs/StageTable.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,17 @@ private[ui] class StageTableBase(
4242
isFairScheduler: Boolean,
4343
killEnabled: Boolean,
4444
isFailedStage: Boolean) {
45-
val allParameters = request.getParameterMap().asScala.toMap
45+
// stripXSS is called to remove suspicious characters used in XSS attacks
46+
val allParameters = request.getParameterMap.asScala.toMap.mapValues(_.map(UIUtils.stripXSS))
4647
val parameterOtherTable = allParameters.filterNot(_._1.startsWith(stageTag))
4748
.map(para => para._1 + "=" + para._2(0))
4849

49-
val parameterStagePage = request.getParameter(stageTag + ".page")
50-
val parameterStageSortColumn = request.getParameter(stageTag + ".sort")
51-
val parameterStageSortDesc = request.getParameter(stageTag + ".desc")
52-
val parameterStagePageSize = request.getParameter(stageTag + ".pageSize")
53-
val parameterStagePrevPageSize = request.getParameter(stageTag + ".prevPageSize")
50+
val parameterStagePage = UIUtils.stripXSS(request.getParameter(stageTag + ".page"))
51+
val parameterStageSortColumn = UIUtils.stripXSS(request.getParameter(stageTag + ".sort"))
52+
val parameterStageSortDesc = UIUtils.stripXSS(request.getParameter(stageTag + ".desc"))
53+
val parameterStagePageSize = UIUtils.stripXSS(request.getParameter(stageTag + ".pageSize"))
54+
val parameterStagePrevPageSize =
55+
UIUtils.stripXSS(request.getParameter(stageTag + ".prevPageSize"))
5456

5557
val stagePage = Option(parameterStagePage).map(_.toInt).getOrElse(1)
5658
val stageSortColumn = Option(parameterStageSortColumn).map { sortColumn =>
@@ -512,4 +514,3 @@ private[ui] class StageDataSource(
512514
}
513515
}
514516
}
515-

core/src/main/scala/org/apache/spark/ui/jobs/StagesTab.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ package org.apache.spark.ui.jobs
2020
import javax.servlet.http.HttpServletRequest
2121

2222
import org.apache.spark.scheduler.SchedulingMode
23-
import org.apache.spark.ui.{SparkUI, SparkUITab}
23+
import org.apache.spark.ui.{SparkUI, SparkUITab, UIUtils}
2424

2525
/** Web UI showing progress status of all stages in the given SparkContext. */
2626
private[ui] class StagesTab(parent: SparkUI) extends SparkUITab(parent, "stages") {
@@ -39,7 +39,8 @@ private[ui] class StagesTab(parent: SparkUI) extends SparkUITab(parent, "stages"
3939

4040
def handleKillRequest(request: HttpServletRequest): Unit = {
4141
if (killEnabled && parent.securityManager.checkModifyPermissions(request.getRemoteUser)) {
42-
val stageId = Option(request.getParameter("id")).map(_.toInt)
42+
// stripXSS is called first to remove suspicious characters used in XSS attacks
43+
val stageId = Option(UIUtils.stripXSS(request.getParameter("id"))).map(_.toInt)
4344
stageId.foreach { id =>
4445
if (progressListener.activeStages.contains(id)) {
4546
sc.foreach(_.cancelStage(id))

core/src/main/scala/org/apache/spark/ui/storage/RDDPage.scala

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@ private[ui] class RDDPage(parent: StorageTab) extends WebUIPage("rdd") {
3131
private val listener = parent.listener
3232

3333
def render(request: HttpServletRequest): Seq[Node] = {
34-
val parameterId = request.getParameter("id")
34+
// stripXSS is called first to remove suspicious characters used in XSS attacks
35+
val parameterId = UIUtils.stripXSS(request.getParameter("id"))
3536
require(parameterId != null && parameterId.nonEmpty, "Missing id parameter")
3637

37-
val parameterBlockPage = request.getParameter("block.page")
38-
val parameterBlockSortColumn = request.getParameter("block.sort")
39-
val parameterBlockSortDesc = request.getParameter("block.desc")
40-
val parameterBlockPageSize = request.getParameter("block.pageSize")
41-
val parameterBlockPrevPageSize = request.getParameter("block.prevPageSize")
38+
val parameterBlockPage = UIUtils.stripXSS(request.getParameter("block.page"))
39+
val parameterBlockSortColumn = UIUtils.stripXSS(request.getParameter("block.sort"))
40+
val parameterBlockSortDesc = UIUtils.stripXSS(request.getParameter("block.desc"))
41+
val parameterBlockPageSize = UIUtils.stripXSS(request.getParameter("block.pageSize"))
42+
val parameterBlockPrevPageSize = UIUtils.stripXSS(request.getParameter("block.prevPageSize"))
4243

4344
val blockPage = Option(parameterBlockPage).map(_.toInt).getOrElse(1)
4445
val blockSortColumn = Option(parameterBlockSortColumn).getOrElse("Block Name")

core/src/test/scala/org/apache/spark/ui/UIUtilsSuite.scala

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,45 @@ class UIUtilsSuite extends SparkFunSuite {
133133
assert(decoded2 === decodeURLParameter(decoded2))
134134
}
135135

136+
test("SPARK-20393: Prevent newline characters in parameters.") {
137+
val encoding = "Encoding:base64%0d%0a%0d%0aPGh0bWw%2bjcmlwdD48L2h0bWw%2b"
138+
val stripEncoding = "Encoding:base64PGh0bWw%2bjcmlwdD48L2h0bWw%2b"
139+
140+
assert(stripEncoding === stripXSS(encoding))
141+
}
142+
143+
test("SPARK-20393: Prevent script from parameters running on page.") {
144+
val scriptAlert = """>"'><script>alert(401)<%2Fscript>"""
145+
val stripScriptAlert = "&gt;&quot;&gt;&lt;script&gt;alert(401)&lt;%2Fscript&gt;"
146+
147+
assert(stripScriptAlert === stripXSS(scriptAlert))
148+
}
149+
150+
test("SPARK-20393: Prevent javascript from parameters running on page.") {
151+
val javascriptAlert =
152+
"""app-20161208133404-0002<iframe+src%3Djavascript%3Aalert(1705)>"""
153+
val stripJavascriptAlert =
154+
"app-20161208133404-0002&lt;iframe+src%3Djavascript%3Aalert(1705)&gt;"
155+
156+
assert(stripJavascriptAlert === stripXSS(javascriptAlert))
157+
}
158+
159+
test("SPARK-20393: Prevent links from parameters on page.") {
160+
val link =
161+
"""stdout'"><iframe+id%3D1131+src%3Dhttp%3A%2F%2Fdemo.test.net%2Fphishing.html>"""
162+
val stripLink =
163+
"stdout&quot;&gt;&lt;iframe+id%3D1131+src%3Dhttp%3A%2F%2Fdemo.test.net%2Fphishing.html&gt;"
164+
165+
assert(stripLink === stripXSS(link))
166+
}
167+
168+
test("SPARK-20393: Prevent popups from parameters on page.") {
169+
val popup = """stdout'%2Balert(60)%2B'"""
170+
val stripPopup = "stdout%2Balert(60)%2B"
171+
172+
assert(stripPopup === stripXSS(popup))
173+
}
174+
136175
private def verify(
137176
desc: String,
138177
expected: Node,

mesos/src/main/scala/org/apache/spark/deploy/mesos/ui/DriverPage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ import org.apache.spark.ui.{UIUtils, WebUIPage}
2929
private[ui] class DriverPage(parent: MesosClusterUI) extends WebUIPage("driver") {
3030

3131
override def render(request: HttpServletRequest): Seq[Node] = {
32-
val driverId = request.getParameter("id")
32+
// stripXSS is called first to remove suspicious characters used in XSS attacks
33+
val driverId = UIUtils.stripXSS(request.getParameter("id"))
3334
require(driverId != null && driverId.nonEmpty, "Missing id parameter")
3435

3536
val state = parent.scheduler.getDriverState(driverId)

sql/core/src/main/scala/org/apache/spark/sql/execution/ui/ExecutionPage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class ExecutionPage(parent: SQLTab) extends WebUIPage("execution") with Logging
2929
private val listener = parent.listener
3030

3131
override def render(request: HttpServletRequest): Seq[Node] = listener.synchronized {
32-
val parameterExecutionId = request.getParameter("id")
32+
// stripXSS is called first to remove suspicious characters used in XSS attacks
33+
val parameterExecutionId = UIUtils.stripXSS(request.getParameter("id"))
3334
require(parameterExecutionId != null && parameterExecutionId.nonEmpty,
3435
"Missing execution id parameter")
3536

sql/hive-thriftserver/src/main/scala/org/apache/spark/sql/hive/thriftserver/ui/ThriftServerSessionPage.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ private[ui] class ThriftServerSessionPage(parent: ThriftServerTab)
3939

4040
/** Render the page */
4141
def render(request: HttpServletRequest): Seq[Node] = {
42-
val parameterId = request.getParameter("id")
42+
// stripXSS is called first to remove suspicious characters used in XSS attacks
43+
val parameterId = UIUtils.stripXSS(request.getParameter("id"))
4344
require(parameterId != null && parameterId.nonEmpty, "Missing id parameter")
4445

4546
val content =
@@ -197,4 +198,3 @@ private[ui] class ThriftServerSessionPage(parent: ThriftServerTab)
197198
UIUtils.listingTable(headers, generateDataRow, data, fixedWidth = true)
198199
}
199200
}
200-

0 commit comments

Comments
 (0)