by Bozho | Jan 6, 2021 | Aggregated, csp, Developer tips, security, spring security
Content-Security-Policy is important for web security. Yet, it’s not mainstream yet, it’s syntax is hard, it’s rather prohibitive and tools rarely have flexible support for it. While Spring Security does have a built-in Content Security Policy (CSP) configuration, it allows you to specify the policy a a string, not build it dynamically. And in some cases you need more than that. In particular, CSP discourages the user of inline javascript, because it introduces vulnerabilities. If you really need it, you can use unsafe-inline but that’s a bad approach, as it negates the whole point of CSP. The alternative presented on that page is to use hash or nonce. I’ll explain how to use nonce with spring security, if you are using .and().headers().contentSecurityPolicy(policy). The policy string is static, so you can’t generate a random nonce for each request. And having a static nonce is useless. So first, you define a CSP nonce filter: public class CSPNonceFilter extends GenericFilterBean { private static final int NONCE_SIZE = 32; //recommended is at least 128 bits/16 bytes private static final String CSP_NONCE_ATTRIBUTE = "cspNonce"; private SecureRandom secureRandom = new SecureRandom(); @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; byte[] nonceArray = new byte[NONCE_SIZE]; secureRandom.nextBytes(nonceArray); String nonce = Base64.getEncoder().encodeToString(nonceArray); request.setAttribute(CSP_NONCE_ATTRIBUTE, nonce); chain.doFilter(request, new CSPNonceResponseWrapper(response, nonce)); } /** * Wrapper to fill the nonce value */ public static class CSPNonceResponseWrapper extends HttpServletResponseWrapper { private String nonce; public CSPNonceResponseWrapper(HttpServletResponse response, String nonce) { super(response); this.nonce = nonce; } @Override public void setHeader(String name, String value) { if (name.equals("Content-Security-Policy") && StringUtils.isNotBlank(value)) { super.setHeader(name,...
Recent Comments