HBASE-14148 Default HBase web pages to be non-framable.
* Sends X-Frame-Options header * configured via hbase.http.filter.xframeoptions.mode * defaults to DENY Signed-off-by: Sean Busbey <busbey@cloudera.com>
This commit is contained in:
parent
32b1064c6c
commit
dc9c2efcc9
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.http;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hbase.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
|
||||||
|
|
||||||
|
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
|
||||||
|
public class ClickjackingPreventionFilter implements Filter {
|
||||||
|
|
||||||
|
private FilterConfig filterConfig;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
this.filterConfig = filterConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest req, ServletResponse res,
|
||||||
|
FilterChain chain)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
HttpServletResponse httpRes = (HttpServletResponse) res;
|
||||||
|
httpRes.addHeader("X-Frame-Options", filterConfig.getInitParameter("xframeoptions"));
|
||||||
|
chain.doFilter(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -533,6 +533,10 @@ public class HttpServer implements FilterContainer {
|
||||||
addDefaultApps(contexts, appDir, conf);
|
addDefaultApps(contexts, appDir, conf);
|
||||||
|
|
||||||
addGlobalFilter("safety", QuotingInputFilter.class.getName(), null);
|
addGlobalFilter("safety", QuotingInputFilter.class.getName(), null);
|
||||||
|
Map<String, String> params = new HashMap<String, String>();
|
||||||
|
params.put("xframeoptions", conf.get("hbase.http.filter.xframeoptions.mode", "DENY"));
|
||||||
|
addGlobalFilter("clickjackingprevention",
|
||||||
|
ClickjackingPreventionFilter.class.getName(), params);
|
||||||
final FilterInitializer[] initializers = getFilterInitializers(conf);
|
final FilterInitializer[] initializers = getFilterInitializers(conf);
|
||||||
if (initializers != null) {
|
if (initializers != null) {
|
||||||
conf = new Configuration(conf);
|
conf = new Configuration(conf);
|
||||||
|
|
|
@ -588,6 +588,29 @@ public class TestHttpServer extends HttpServerFunctionalTest {
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testXFrameHeaderSameOrigin() throws Exception {
|
||||||
|
Configuration conf = new Configuration();
|
||||||
|
conf.set("hbase.http.filter.xframeoptions.mode", "SAMEORIGIN");
|
||||||
|
|
||||||
|
HttpServer myServer = new HttpServer.Builder().setName("test")
|
||||||
|
.addEndpoint(new URI("http://localhost:0"))
|
||||||
|
.setFindPort(true).setConf(conf).build();
|
||||||
|
myServer.setAttribute(HttpServer.CONF_CONTEXT_ATTRIBUTE, conf);
|
||||||
|
myServer.addServlet("echo", "/echo", EchoServlet.class);
|
||||||
|
myServer.start();
|
||||||
|
|
||||||
|
String serverURL = "http://"
|
||||||
|
+ NetUtils.getHostPortString(myServer.getConnectorAddress(0));
|
||||||
|
URL url = new URL(new URL(serverURL), "/echo?a=b&c=d");
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
|
assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
|
||||||
|
assertEquals("SAMEORIGIN", conn.getHeaderField("X-Frame-Options"));
|
||||||
|
myServer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoCacheHeader() throws Exception {
|
public void testNoCacheHeader() throws Exception {
|
||||||
URL url = new URL(baseUrl, "/echo?a=b&c=d");
|
URL url = new URL(baseUrl, "/echo?a=b&c=d");
|
||||||
|
@ -598,6 +621,7 @@ public class TestHttpServer extends HttpServerFunctionalTest {
|
||||||
assertNotNull(conn.getHeaderField("Expires"));
|
assertNotNull(conn.getHeaderField("Expires"));
|
||||||
assertNotNull(conn.getHeaderField("Date"));
|
assertNotNull(conn.getHeaderField("Date"));
|
||||||
assertEquals(conn.getHeaderField("Expires"), conn.getHeaderField("Date"));
|
assertEquals(conn.getHeaderField("Expires"), conn.getHeaderField("Date"));
|
||||||
|
assertEquals("DENY", conn.getHeaderField("X-Frame-Options"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue