Skip to content

Commit 5dbaf3d

Browse files
committed
[SPARK-10589] [WEBUI] Add defense against external site framing
Set `X-Frame-Options: SAMEORIGIN` to protect against frame-related vulnerability Author: Sean Owen <[email protected]> Closes #8745 from srowen/SPARK-10589.
1 parent d9b7f3e commit 5dbaf3d

File tree

5 files changed

+24
-11
lines changed

5 files changed

+24
-11
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ package org.apache.spark.deploy.worker.ui
2020
import java.io.File
2121
import javax.servlet.http.HttpServletRequest
2222

23-
import org.apache.spark.{Logging, SparkConf}
23+
import org.apache.spark.Logging
2424
import org.apache.spark.deploy.worker.Worker
25-
import org.apache.spark.deploy.worker.ui.WorkerWebUI._
2625
import org.apache.spark.ui.{SparkUI, WebUI}
2726
import org.apache.spark.ui.JettyUtils._
2827
import org.apache.spark.util.RpcUtils
@@ -49,7 +48,9 @@ class WorkerWebUI(
4948
attachPage(new WorkerPage(this))
5049
attachHandler(createStaticHandler(WorkerWebUI.STATIC_RESOURCE_BASE, "/static"))
5150
attachHandler(createServletHandler("/log",
52-
(request: HttpServletRequest) => logPage.renderLog(request), worker.securityMgr))
51+
(request: HttpServletRequest) => logPage.renderLog(request),
52+
worker.securityMgr,
53+
worker.conf))
5354
}
5455
}
5556

core/src/main/scala/org/apache/spark/metrics/MetricsSystem.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private[spark] class MetricsSystem private (
8888
*/
8989
def getServletHandlers: Array[ServletContextHandler] = {
9090
require(running, "Can only call getServletHandlers on a running MetricsSystem")
91-
metricsServlet.map(_.getHandlers).getOrElse(Array())
91+
metricsServlet.map(_.getHandlers(conf)).getOrElse(Array())
9292
}
9393

9494
metricsConfig.initialize()

core/src/main/scala/org/apache/spark/metrics/sink/MetricsServlet.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import com.codahale.metrics.json.MetricsModule
2727
import com.fasterxml.jackson.databind.ObjectMapper
2828
import org.eclipse.jetty.servlet.ServletContextHandler
2929

30-
import org.apache.spark.SecurityManager
30+
import org.apache.spark.{SparkConf, SecurityManager}
3131
import org.apache.spark.ui.JettyUtils._
3232

3333
private[spark] class MetricsServlet(
@@ -49,10 +49,10 @@ private[spark] class MetricsServlet(
4949
val mapper = new ObjectMapper().registerModule(
5050
new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, servletShowSample))
5151

52-
def getHandlers: Array[ServletContextHandler] = {
52+
def getHandlers(conf: SparkConf): Array[ServletContextHandler] = {
5353
Array[ServletContextHandler](
5454
createServletHandler(servletPath,
55-
new ServletParams(request => getMetricsSnapshot(request), "text/json"), securityMgr)
55+
new ServletParams(request => getMetricsSnapshot(request), "text/json"), securityMgr, conf)
5656
)
5757
}
5858

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,17 @@ private[spark] object JettyUtils extends Logging {
5959

6060
def createServlet[T <% AnyRef](
6161
servletParams: ServletParams[T],
62-
securityMgr: SecurityManager): HttpServlet = {
62+
securityMgr: SecurityManager,
63+
conf: SparkConf): HttpServlet = {
64+
65+
// SPARK-10589 avoid frame-related click-jacking vulnerability, using X-Frame-Options
66+
// (see http://tools.ietf.org/html/rfc7034). By default allow framing only from the
67+
// same origin, but allow framing for a specific named URI.
68+
// Example: spark.ui.allowFramingFrom = https://example.com/
69+
val allowFramingFrom = conf.getOption("spark.ui.allowFramingFrom")
70+
val xFrameOptionsValue =
71+
allowFramingFrom.map(uri => s"ALLOW-FROM $uri").getOrElse("SAMEORIGIN")
72+
6373
new HttpServlet {
6474
override def doGet(request: HttpServletRequest, response: HttpServletResponse) {
6575
try {
@@ -68,6 +78,7 @@ private[spark] object JettyUtils extends Logging {
6878
response.setStatus(HttpServletResponse.SC_OK)
6979
val result = servletParams.responder(request)
7080
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate")
81+
response.setHeader("X-Frame-Options", xFrameOptionsValue)
7182
// scalastyle:off println
7283
response.getWriter.println(servletParams.extractFn(result))
7384
// scalastyle:on println
@@ -97,8 +108,9 @@ private[spark] object JettyUtils extends Logging {
97108
path: String,
98109
servletParams: ServletParams[T],
99110
securityMgr: SecurityManager,
111+
conf: SparkConf,
100112
basePath: String = ""): ServletContextHandler = {
101-
createServletHandler(path, createServlet(servletParams, securityMgr), basePath)
113+
createServletHandler(path, createServlet(servletParams, securityMgr, conf), basePath)
102114
}
103115

104116
/** Create a context handler that responds to a request with the given path prefix */

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ private[spark] abstract class WebUI(
7676
def attachPage(page: WebUIPage) {
7777
val pagePath = "/" + page.prefix
7878
val renderHandler = createServletHandler(pagePath,
79-
(request: HttpServletRequest) => page.render(request), securityManager, basePath)
79+
(request: HttpServletRequest) => page.render(request), securityManager, conf, basePath)
8080
val renderJsonHandler = createServletHandler(pagePath.stripSuffix("/") + "/json",
81-
(request: HttpServletRequest) => page.renderJson(request), securityManager, basePath)
81+
(request: HttpServletRequest) => page.renderJson(request), securityManager, conf, basePath)
8282
attachHandler(renderHandler)
8383
attachHandler(renderJsonHandler)
8484
pageToHandlers.getOrElseUpdate(page, ArrayBuffer[ServletContextHandler]())

0 commit comments

Comments
 (0)