Home > Back-end >  HTTP Content-Security-Policy header not working correctly for script-src in Struts
HTTP Content-Security-Policy header not working correctly for script-src in Struts

Time:01-27

I have a problem updating my version of struts struts2-core-2.5.30 project to struts2-core-6.1.1 so I began to receive an error indicating that the security policies have been violated, doing some research, I found that a header should be added

[Report Only] Refused to load the script '<URL>' because it violates the following Content Security Policy directive: "script-src 'nonce-MOz6w31eaDHGUDfV__K8LEZ1' 'strict-dynamic' http: https:". Note that 'strict-dynamic' is present, so host-based allowlisting is disabled. Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

and inside this error i have this description

[Report Only] Refused to load the script 'http://localhost:8080/Portal/html/js/jquery/jquery-1.8.3.min.js' because it violates the following Content Security Policy directive: "script-src 'nonce-MOz6w31eaDHGUDfV__K8LEZ1' 'strict-dynamic' http: https:". Note that 'strict-dynamic' is present, so host-based allowlisting is disabled. Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

[Report Only] Refused to load the script 'http://localhost:8080/Portal/html/js/jquery/jquery-ui.1.10.4.min.js' because it violates the following Content Security Policy directive: "script-src 'nonce-MOz6w31eaDHGUDfV__K8LEZ1' 'strict-dynamic' http: https:". Note that 'strict-dynamic' is present, so host-based allowlisting is disabled. Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

however I have tried these headers

<meta http-equiv="Content-Security-Policy" content="default-src 'self'">


<meta http-equiv="Content-Security-Policy" content="default-src *;
    style-src * 'unsafe-inline'; script-src * 'unsafe-inline'
    'unsafe-eval'; img-src * data: 'unsafe-inline'; connect-src *
    'unsafe-inline'; frame-src *;">

<meta http-equiv="Content-Security-Policy" content="default-src  'nonce-rAnd0m'">
<script src="${pageContext.request.contextPath}/html/js/jquery/jquery-1.8.3.min.js" type="text/javascript" nonce="rAnd0m123"></script> 

with each of them I get the same error, In my previous version of struts it did not ask me for any of this

have also tried to make an interceptor to add the corresponding directives, however it has not worked for me either.

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.StrutsStatics;


public class SessionInterceptor extends AbstractInterceptor{

   private static final long serialVersionUID = 1L;


   public String intercept(ActionInvocation invocation) throws Exception {
     
    ActionContext ac = invocation.getInvocationContext();
    HttpServletResponse response = (HttpServletResponse) ac.get(StrutsStatics.HTTP_RESPONSE);
    //HttpServletResponse response = ServletActionContext.getResponse();

    response.addHeader("X-Frame-Options", "SAMEORIGIN");
    response.addHeader("Content-Security-Policy-Report-Only", "default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self'; media-src 'none'; frame-src 'none'; font-src 'self'; connect-src 'self'; report-uri REDACTED");
    response.addHeader("X-Content-Security-Policy-Report-Only", "default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self'; media-src 'none'; frame-src 'none'; font-src 'self'; connect-src 'self'; report-uri REDACTED");
    return invocation.invoke();
}

}

In the same way I have updated the jquery-1.8.3 version as suggested in the comments but it has not worked for me either

CodePudding user response:

The content of your policies and the one in the error message don't match, and while you are adding "Content-Security-Policy", the error message is for "Content-Security-Policy-Report-Only". This means that there is another header present, and you are adding another. Adding another can only make the policy stricter. The report only version of Content-Security-Policy doesn't actually block anything, and must be set as a response header. You should identify where this header is set and modify it as needed.

Additionally you should replace jquery-1.8.3 with a recent version that doesn't have known vulnerabilities.

CodePudding user response:

It has been a very long time without using Struts: please, forgive me for any inaccuracy.

Struts provides support for Content-Security-Policy since version 6.x.

The functionality is implemented primarily in CspInterceptor.

This interceptor is configured by providing a convenient default implementation of CspSettings.

This interceptor is included by default in the Struts configuration. As you can see in the linked resource and in the documentation by default is configured in report only, non enforcing mode:

<interceptor-ref name="csp">
  <param name="disabled">false</param>
  <param name="enforcingMode">false</param>
</interceptor-ref>

I reviewed the current source code of the library and the companion documentation and it seems that providing a custom CSP configuration to CspInterceptor is not possible right now.

That means that in order to mitigate your error one possibility will be to disable the CspInterceptor and provide your own. The Struts documentation provides guidance about how it could be accomplished. In your case, I think it should look like similar to the following:

<action name="myAction" >
    <interceptor-ref name="defaultStack">
        <param name="csp.disabled">true</param>
    </interceptor-ref>
</action>

In addition, in the commit I cited at the beginning of the answer they mention the components and corresponding tags s:link and s:script as a possible way for fetching the required CSS and Javascript resources taking into account the CSP settings. Please, consider review for instance this page in the showcase they provide as example, reproduced here for convenience:

<%@taglib prefix="s" uri="/struts-tags" %>


<html lang="en">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Struts2 Showcase for Apache Struts Project">
    <meta name="author" content="The Apache Software Foundation">


    <title><decorator:title default="Struts2 Showcase"/></title>


    <s:url var="bootstrapCss" value='/styles/bootstrap.css' encode='false' includeParams='none'/>
    <s:link href="%{bootstrapCss}" rel="stylesheet" type="text/css" media="all"/>
    <s:url var="mainCss" value='/styles/main.css' encode='false' includeParams='none'/>
    <s:link href="%{mainCss}" rel="stylesheet" type="text/css" media="all"/>


    <s:url var="jqueryJs" value='/js/jquery-2.1.4.min.js' encode='false' includeParams='none'/>
    <s:script src="%{jqueryJs}"/>
    <s:url var="bootstrapJs" value='/js/bootstrap.min.js' encode='false' includeParams='none'/>
    <s:script src="%{bootstrapJs}"/>
    <s:script type="text/javascript">
        $(function () {
            var alerts = $('ul.alert').wrap('<div />');
            alerts.prepend('<a  data-dismiss="alert" href="#">&times;</a>');
            alerts.alert();
        });
    </s:script>


    <!-- Prettify -->
    <s:url var="prettifyCss" value='/styles/prettify.css' encode='false' includeParams='none'/>
    <s:link href="%{prettifyCss}" rel="stylesheet"/>
    <s:url var="prettifyJs" value='/js/prettify.js' encode='false' includeParams='none'/>
    <s:script src="%{prettifyJs}"/>


    <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
    <!--[if lt IE 9]>
    <s:script src="http://html5shim.googlecode.com/svn/trunk/html5.js"/>
    <![endif]-->


    <s:script>
        jQuery(document).ready(function() { prettyPrint(); } );
    </s:script>
    <decorator:head/>
</head>
  • Related