aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorSean Owen <sowen@cloudera.com>2015-09-16 19:19:23 +0100
committerSean Owen <sowen@cloudera.com>2015-09-16 19:19:23 +0100
commit5dbaf3d3911bbfa003bc75459aaad66b4f6e0c67 (patch)
tree13ac6b627a131fd1a2dcee7fd5174fe4261edb7f /core
parentd9b7f3e4dbceb91ea4d1a1fed3ab847335f8588b (diff)
downloadspark-5dbaf3d3911bbfa003bc75459aaad66b4f6e0c67.tar.gz
spark-5dbaf3d3911bbfa003bc75459aaad66b4f6e0c67.tar.bz2
spark-5dbaf3d3911bbfa003bc75459aaad66b4f6e0c67.zip
[SPARK-10589] [WEBUI] Add defense against external site framing
Set `X-Frame-Options: SAMEORIGIN` to protect against frame-related vulnerability Author: Sean Owen <sowen@cloudera.com> Closes #8745 from srowen/SPARK-10589.
Diffstat (limited to 'core')
-rw-r--r--core/src/main/scala/org/apache/spark/deploy/worker/ui/WorkerWebUI.scala7
-rw-r--r--core/src/main/scala/org/apache/spark/metrics/MetricsSystem.scala2
-rw-r--r--core/src/main/scala/org/apache/spark/metrics/sink/MetricsServlet.scala6
-rw-r--r--core/src/main/scala/org/apache/spark/ui/JettyUtils.scala16
-rw-r--r--core/src/main/scala/org/apache/spark/ui/WebUI.scala4
5 files changed, 24 insertions, 11 deletions
diff --git a/core/src/main/scala/org/apache/spark/deploy/worker/ui/WorkerWebUI.scala b/core/src/main/scala/org/apache/spark/deploy/worker/ui/WorkerWebUI.scala
index 709a272335..1a0598e50d 100644
--- a/core/src/main/scala/org/apache/spark/deploy/worker/ui/WorkerWebUI.scala
+++ b/core/src/main/scala/org/apache/spark/deploy/worker/ui/WorkerWebUI.scala
@@ -20,9 +20,8 @@ package org.apache.spark.deploy.worker.ui
import java.io.File
import javax.servlet.http.HttpServletRequest
-import org.apache.spark.{Logging, SparkConf}
+import org.apache.spark.Logging
import org.apache.spark.deploy.worker.Worker
-import org.apache.spark.deploy.worker.ui.WorkerWebUI._
import org.apache.spark.ui.{SparkUI, WebUI}
import org.apache.spark.ui.JettyUtils._
import org.apache.spark.util.RpcUtils
@@ -49,7 +48,9 @@ class WorkerWebUI(
attachPage(new WorkerPage(this))
attachHandler(createStaticHandler(WorkerWebUI.STATIC_RESOURCE_BASE, "/static"))
attachHandler(createServletHandler("/log",
- (request: HttpServletRequest) => logPage.renderLog(request), worker.securityMgr))
+ (request: HttpServletRequest) => logPage.renderLog(request),
+ worker.securityMgr,
+ worker.conf))
}
}
diff --git a/core/src/main/scala/org/apache/spark/metrics/MetricsSystem.scala b/core/src/main/scala/org/apache/spark/metrics/MetricsSystem.scala
index 4517f465eb..48afe3ae35 100644
--- a/core/src/main/scala/org/apache/spark/metrics/MetricsSystem.scala
+++ b/core/src/main/scala/org/apache/spark/metrics/MetricsSystem.scala
@@ -88,7 +88,7 @@ private[spark] class MetricsSystem private (
*/
def getServletHandlers: Array[ServletContextHandler] = {
require(running, "Can only call getServletHandlers on a running MetricsSystem")
- metricsServlet.map(_.getHandlers).getOrElse(Array())
+ metricsServlet.map(_.getHandlers(conf)).getOrElse(Array())
}
metricsConfig.initialize()
diff --git a/core/src/main/scala/org/apache/spark/metrics/sink/MetricsServlet.scala b/core/src/main/scala/org/apache/spark/metrics/sink/MetricsServlet.scala
index 0c2e212a33..4193e1d21d 100644
--- a/core/src/main/scala/org/apache/spark/metrics/sink/MetricsServlet.scala
+++ b/core/src/main/scala/org/apache/spark/metrics/sink/MetricsServlet.scala
@@ -27,7 +27,7 @@ import com.codahale.metrics.json.MetricsModule
import com.fasterxml.jackson.databind.ObjectMapper
import org.eclipse.jetty.servlet.ServletContextHandler
-import org.apache.spark.SecurityManager
+import org.apache.spark.{SparkConf, SecurityManager}
import org.apache.spark.ui.JettyUtils._
private[spark] class MetricsServlet(
@@ -49,10 +49,10 @@ private[spark] class MetricsServlet(
val mapper = new ObjectMapper().registerModule(
new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, servletShowSample))
- def getHandlers: Array[ServletContextHandler] = {
+ def getHandlers(conf: SparkConf): Array[ServletContextHandler] = {
Array[ServletContextHandler](
createServletHandler(servletPath,
- new ServletParams(request => getMetricsSnapshot(request), "text/json"), securityMgr)
+ new ServletParams(request => getMetricsSnapshot(request), "text/json"), securityMgr, conf)
)
}
diff --git a/core/src/main/scala/org/apache/spark/ui/JettyUtils.scala b/core/src/main/scala/org/apache/spark/ui/JettyUtils.scala
index 779c0ba083..b796a44fe0 100644
--- a/core/src/main/scala/org/apache/spark/ui/JettyUtils.scala
+++ b/core/src/main/scala/org/apache/spark/ui/JettyUtils.scala
@@ -59,7 +59,17 @@ private[spark] object JettyUtils extends Logging {
def createServlet[T <% AnyRef](
servletParams: ServletParams[T],
- securityMgr: SecurityManager): HttpServlet = {
+ securityMgr: SecurityManager,
+ conf: SparkConf): HttpServlet = {
+
+ // SPARK-10589 avoid frame-related click-jacking vulnerability, using X-Frame-Options
+ // (see http://tools.ietf.org/html/rfc7034). By default allow framing only from the
+ // same origin, but allow framing for a specific named URI.
+ // Example: spark.ui.allowFramingFrom = https://example.com/
+ val allowFramingFrom = conf.getOption("spark.ui.allowFramingFrom")
+ val xFrameOptionsValue =
+ allowFramingFrom.map(uri => s"ALLOW-FROM $uri").getOrElse("SAMEORIGIN")
+
new HttpServlet {
override def doGet(request: HttpServletRequest, response: HttpServletResponse) {
try {
@@ -68,6 +78,7 @@ private[spark] object JettyUtils extends Logging {
response.setStatus(HttpServletResponse.SC_OK)
val result = servletParams.responder(request)
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate")
+ response.setHeader("X-Frame-Options", xFrameOptionsValue)
// scalastyle:off println
response.getWriter.println(servletParams.extractFn(result))
// scalastyle:on println
@@ -97,8 +108,9 @@ private[spark] object JettyUtils extends Logging {
path: String,
servletParams: ServletParams[T],
securityMgr: SecurityManager,
+ conf: SparkConf,
basePath: String = ""): ServletContextHandler = {
- createServletHandler(path, createServlet(servletParams, securityMgr), basePath)
+ createServletHandler(path, createServlet(servletParams, securityMgr, conf), basePath)
}
/** Create a context handler that responds to a request with the given path prefix */
diff --git a/core/src/main/scala/org/apache/spark/ui/WebUI.scala b/core/src/main/scala/org/apache/spark/ui/WebUI.scala
index 61449847ad..81a121fd44 100644
--- a/core/src/main/scala/org/apache/spark/ui/WebUI.scala
+++ b/core/src/main/scala/org/apache/spark/ui/WebUI.scala
@@ -76,9 +76,9 @@ private[spark] abstract class WebUI(
def attachPage(page: WebUIPage) {
val pagePath = "/" + page.prefix
val renderHandler = createServletHandler(pagePath,
- (request: HttpServletRequest) => page.render(request), securityManager, basePath)
+ (request: HttpServletRequest) => page.render(request), securityManager, conf, basePath)
val renderJsonHandler = createServletHandler(pagePath.stripSuffix("/") + "/json",
- (request: HttpServletRequest) => page.renderJson(request), securityManager, basePath)
+ (request: HttpServletRequest) => page.renderJson(request), securityManager, conf, basePath)
attachHandler(renderHandler)
attachHandler(renderJsonHandler)
pageToHandlers.getOrElseUpdate(page, ArrayBuffer[ServletContextHandler]())