You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2018/09/06 00:39:47 UTC

nifi git commit: NIFI-5366 - Added ContentSecurityPolicyFilter which stops framing of NiFi resources. It applies the Content-Security-Policy header. This protects against clickjacking. NIFI-5366 - Added unit test. Added single quotes around 'self' for fr

Repository: nifi
Updated Branches:
  refs/heads/master 4f0e2f556 -> fc1461298


NIFI-5366 - Added ContentSecurityPolicyFilter which stops framing of NiFi resources. It applies the Content-Security-Policy header. This protects against clickjacking.
NIFI-5366 - Added unit test. Added single quotes around 'self' for frame-ancestors CSP header.
NIFI-5366 - Fixed dependencies.

This closes #2989.

Signed-off-by: Andy LoPresto <al...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/fc146129
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/fc146129
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/fc146129

Branch: refs/heads/master
Commit: fc1461298a0a137d0fae3cd3b494fc6dec25070a
Parents: 4f0e2f5
Author: thenatog <th...@gmail.com>
Authored: Fri Aug 31 19:50:15 2018 -0400
Committer: Andy LoPresto <al...@apache.org>
Committed: Wed Sep 5 17:38:53 2018 -0700

----------------------------------------------------------------------
 .../org/apache/nifi/web/server/JettyServer.java |  6 ++
 .../nifi-web/nifi-web-security/pom.xml          | 11 +++
 .../security/ContentSecurityPolicyFilter.java   | 57 ++++++++++++++++
 .../ContentSecurityPolicyFilterTest.java        | 70 ++++++++++++++++++++
 4 files changed, 144 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/fc146129/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java
index 66ecd45..3bf98ca 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java
@@ -74,6 +74,7 @@ import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.ContentAccess;
 import org.apache.nifi.web.NiFiWebConfigurationContext;
 import org.apache.nifi.web.UiExtensionType;
+import org.apache.nifi.web.security.ContentSecurityPolicyFilter;
 import org.eclipse.jetty.annotations.AnnotationConfiguration;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
@@ -502,6 +503,11 @@ public class JettyServer implements NiFiServer {
         // add a filter to set the X-Frame-Options filter
         webappContext.addFilter(new FilterHolder(FRAME_OPTIONS_FILTER), "/*", EnumSet.allOf(DispatcherType.class));
 
+        // add a filter to set the Content Security Policy frame-ancestors directive
+        FilterHolder cspFilter = new FilterHolder(new ContentSecurityPolicyFilter());
+        cspFilter.setName(ContentSecurityPolicyFilter.class.getSimpleName());
+        webappContext.addFilter(cspFilter, "/*", EnumSet.allOf(DispatcherType.class));
+
         try {
             // configure the class loader - webappClassLoader -> jetty nar -> web app's nar -> ...
             webappContext.setClassLoader(new WebAppClassLoader(parentClassLoader, webappContext));

http://git-wip-us.apache.org/repos/asf/nifi/blob/fc146129/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
index 75a19a3..646b7e8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
@@ -154,5 +154,16 @@
             <artifactId>jettison</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <version>5.0.6.RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/fc146129/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ContentSecurityPolicyFilter.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ContentSecurityPolicyFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ContentSecurityPolicyFilter.java
new file mode 100644
index 0000000..0f8a977
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ContentSecurityPolicyFilter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.nifi.web.security;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+
+/**
+ * A filter to apply the Content Security Policy (which supersedes the X-Frame-Options header).
+ *
+ */
+public class ContentSecurityPolicyFilter implements Filter {
+    private static final String HEADER = "Content-Security-Policy";
+    private static final String POLICY = "frame-ancestors 'self'";
+
+    private static final Logger logger = LoggerFactory.getLogger(ContentSecurityPolicyFilter.class);
+
+    @Override
+    public void doFilter(final ServletRequest req, final ServletResponse resp, final FilterChain filterChain)
+            throws IOException, ServletException {
+
+        final HttpServletResponse response = (HttpServletResponse) resp;
+        response.setHeader(HEADER, POLICY);
+
+        filterChain.doFilter(req, resp);
+    }
+
+    @Override
+    public void init(final FilterConfig config) {
+    }
+
+    @Override
+    public void destroy() {
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/fc146129/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/ContentSecurityPolicyFilterTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/ContentSecurityPolicyFilterTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/ContentSecurityPolicyFilterTest.java
new file mode 100644
index 0000000..7bfb9a4
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/ContentSecurityPolicyFilterTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.nifi.web.security;
+
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+
+public class ContentSecurityPolicyFilterTest {
+
+    @Test
+    public void testCSPHeaderApplied() throws ServletException, IOException {
+        // Arrange
+
+        FilterHolder originFilter = new FilterHolder(new ContentSecurityPolicyFilter());
+
+        // Set up request
+        HttpServletRequest mockRequest = Mockito.mock(HttpServletRequest.class);
+        MockHttpServletResponse mockResponse = new MockHttpServletResponse();
+        FilterChain mockFilterChain = Mockito.mock(FilterChain.class);
+
+        // Action
+        originFilter.getFilter().doFilter(mockRequest, mockResponse, mockFilterChain);
+
+        // Verify
+        assertEquals("frame-ancestors 'self'", mockResponse.getHeader("Content-Security-Policy"));
+    }
+
+    @Test
+    public void testCSPHeaderAppliedOnlyOnce() throws ServletException, IOException {
+        // Arrange
+
+        FilterHolder originFilter = new FilterHolder(new ContentSecurityPolicyFilter());
+
+        // Set up request
+        HttpServletRequest mockRequest = Mockito.mock(HttpServletRequest.class);
+        MockHttpServletResponse mockResponse = new MockHttpServletResponse();
+        FilterChain mockFilterChain = Mockito.mock(FilterChain.class);
+
+        // Action
+        originFilter.getFilter().doFilter(mockRequest, mockResponse, mockFilterChain);
+        originFilter.getFilter().doFilter(mockRequest, mockResponse, mockFilterChain);
+
+        // Verify
+        assertEquals("frame-ancestors 'self'", mockResponse.getHeader("Content-Security-Policy"));
+    }
+
+}
\ No newline at end of file