/** Sets mandatory headers, notably for anti-clickjacking. */ @Override public void setCSPHeaders(DefDescriptor<?> top, HttpServletRequest req, HttpServletResponse rsp) { if (canSkipCSPHeader(top, req)) { return; } ContentSecurityPolicy csp = configAdapter.getContentSecurityPolicy(top == null ? null : top.getQualifiedName(), req); if (csp != null) { rsp.setHeader(CSP.Header.SECURE, csp.getCspHeaderValue()); Collection<String> terms = csp.getFrameAncestors(); if (terms != null) { // not open to the world; figure whether we can express an X-FRAME-OPTIONS header: if (terms.size() == 0) { // closed to any framing at all rsp.setHeader(HDR_FRAME_OPTIONS, HDR_FRAME_DENY); } else if (terms.size() == 1) { // With one ancestor term, we're either SAMEORIGIN or ALLOWFROM for (String site : terms) { if (site == null) { // Add same-origin headers and policy terms rsp.addHeader(HDR_FRAME_OPTIONS, HDR_FRAME_SAMEORIGIN); } else if (!site.contains("*") && !site.matches("^[a-z]+:$")) { // XFO can't express wildcards or protocol-only, so set only for a specific site: rsp.addHeader(HDR_FRAME_OPTIONS, HDR_FRAME_ALLOWFROM + site); } else { // When XFO can't express it, still set an ALLOWALL so filters don't jump in rsp.addHeader(HDR_FRAME_OPTIONS, HDR_FRAME_ALLOWALL); } } } } } }