CspEnforcementFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (request == null || response == null || !(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { chain.doFilter(request, response); return; } HttpServletRequest httpServletRequest = (HttpServletRequest)request; HttpServletResponse httpServletResponse = (HttpServletResponse)response; if (REPORT_URI.equals(httpServletRequest.getRequestURI())) { JSONObject json = new JSONObject(IOUtil.toString(httpServletRequest.getInputStream())); json = json.getJSONObject("csp-report"); try { String violatedDirectiveName = json.getString("violated-directive").split(" ")[0]; URI documentUri = new URI(json.getString("document-uri")); String blocked = json.getString("blocked-uri"); if (blocked.equals("self") && (violatedDirectiveName.equals("script-src") || violatedDirectiveName.equals("style-src"))) { blocked = "'unsafe-inline'"; } if (blocked.charAt(0) != '\'') { if (getHostPart(documentUri).equals(getHostPart(new URI(blocked)))) { blocked = "'self'"; } } policy.logViolation(documentUri, violatedDirectiveName, blocked); } catch (JSONException | URISyntaxException e) { throw new IllegalArgumentException("Invalid request", e); } return; } if (policy != null) { String policyStr = policy.getPolicyForUri(httpServletRequest.getRequestURI()); policyStr += "; report-uri " + REPORT_URI; if (policyConfig.isReportOnlyMode()) { httpServletResponse.addHeader("Content-Security-Policy-Report-Only", policyStr); } else { httpServletResponse.addHeader("Content-Security-Policy", policyStr); } } chain.doFilter(request, response); } CspEnforcementFilter(CspPolicy policy, PolicyConfig policyConfig); @Override void doFilter(ServletRequest request, ServletResponse response, FilterChain chain); @Override void init(FilterConfig filterConfig); @Override void destroy(); static final String REPORT_URI; }
@Test public void testBasicViolationReport() throws IOException, ServletException, URISyntaxException { CspPolicy policy = createMock(CspPolicy.class); policy.logViolation(new URI("http: expectLastCall(); PolicyConfig policyConfig = createMock(PolicyConfig.class); expect(policyConfig.isReportOnlyMode()).andReturn(false).anyTimes(); replay(policy, policyConfig); CspEnforcementFilter cspEnforcementFilter = new CspEnforcementFilter(policy, policyConfig); HttpServletRequest request = createMock(HttpServletRequest.class); expect(request.getRequestURI()).andReturn(CspEnforcementFilter.REPORT_URI); expect(request.getInputStream()).andReturn(new DelegateServletInputStream(new ByteArrayInputStream( ("{\"csp-report\":{" + "\"document-uri\": \"http: + "\"blocked-uri\": \"http: + "\"violated-directive\": \"script-src self\"" + "}}") .getBytes(StandardCharsets.UTF_8)))); HttpServletResponse response = createMock(HttpServletResponse.class); FilterChain chain = createStrictMock(FilterChain.class); replay(request, response, chain); cspEnforcementFilter.doFilter(request, response, chain); verify(request, response, chain); verify(policy, policyConfig); }
@Test public void testSelfViolationReport() throws IOException, ServletException, URISyntaxException { CspPolicy policy = createMock(CspPolicy.class); policy.logViolation(new URI("http: expectLastCall(); PolicyConfig policyConfig = createMock(PolicyConfig.class); expect(policyConfig.isReportOnlyMode()).andReturn(false).anyTimes(); replay(policy, policyConfig); CspEnforcementFilter cspEnforcementFilter = new CspEnforcementFilter(policy, policyConfig); HttpServletRequest request = createMock(HttpServletRequest.class); expect(request.getRequestURI()).andReturn(CspEnforcementFilter.REPORT_URI); expect(request.getInputStream()).andReturn(new DelegateServletInputStream(new ByteArrayInputStream( ("{\"csp-report\":{" + "\"document-uri\": \"http: + "\"blocked-uri\": \"http: + "\"violated-directive\": \"script-src none\"" + "}}") .getBytes(StandardCharsets.UTF_8)))); HttpServletResponse response = createMock(HttpServletResponse.class); FilterChain chain = createStrictMock(FilterChain.class); replay(request, response, chain); cspEnforcementFilter.doFilter(request, response, chain); verify(request, response, chain); verify(policy, policyConfig); }
@Test public void testUnsafeInlineViolationReport() throws IOException, ServletException, URISyntaxException { CspPolicy policy = createMock(CspPolicy.class); policy.logViolation(new URI("http: expectLastCall(); PolicyConfig policyConfig = createMock(PolicyConfig.class); expect(policyConfig.isReportOnlyMode()).andReturn(false).anyTimes(); replay(policy, policyConfig); CspEnforcementFilter cspEnforcementFilter = new CspEnforcementFilter(policy, policyConfig); HttpServletRequest request = createMock(HttpServletRequest.class); expect(request.getRequestURI()).andReturn(CspEnforcementFilter.REPORT_URI); expect(request.getInputStream()).andReturn(new DelegateServletInputStream(new ByteArrayInputStream( ("{\"csp-report\":{" + "\"document-uri\": \"http: + "\"blocked-uri\": \"self\"," + "\"violated-directive\": \"script-src none\"" + "}}") .getBytes(StandardCharsets.UTF_8)))); HttpServletResponse response = createMock(HttpServletResponse.class); FilterChain chain = createStrictMock(FilterChain.class); replay(request, response, chain); cspEnforcementFilter.doFilter(request, response, chain); verify(request, response, chain); verify(policy, policyConfig); }