This is an automated email from the ASF dual-hosted git repository.

jleroux pushed a commit to branch POC-for-CSRF-Token-OFBIZ-11306
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git

commit 69b551038801e53c1cd3b8c03ddf1fab0198c3fc
Author: Jacques Le Roux <jacques.le.r...@les7arts.com>
AuthorDate: Wed Feb 26 15:41:23 2020 +0100

    Creates new POC-for-CSRF-Token-OFBIZ-11306 branch
    
    To share with James and others and later when OK to create a PR
---
 .../humanres/template/category/CategoryTree.ftl    |  16 +-
 .../category/ftl/CatalogAltUrlSeoTransform.java    |   8 +-
 .../product/category/ftl/UrlRegexpTransform.java   |  13 +-
 .../product/template/category/CategoryTree.ftl     |   2 +-
 .../java/org/apache/ofbiz/common/CommonEvents.java |   3 +-
 .../common/webcommon/WEB-INF/common-controller.xml |   7 +-
 framework/security/config/security.properties      |  23 +-
 .../apache/ofbiz/security/CsrfDefenseStrategy.java |  93 ++++++
 .../java/org/apache/ofbiz/security/CsrfUtil.java   | 358 +++++++++++++++++++++
 .../ofbiz/security/ICsrfDefenseStrategy.java       |  55 ++++
 .../ofbiz/security/NoCsrfDefenseStrategy.java      |  50 +++
 .../org/apache/ofbiz/security/CsrfUtilTests.java   | 264 +++++++++++++++
 framework/webapp/dtd/site-conf.xsd                 |  14 +
 .../ofbiz/webapp/control/ConfigXMLReader.java      |   3 +
 .../ofbiz/webapp/control/ControlEventListener.java |   3 +
 .../ofbiz/webapp/control/RequestHandler.java       |  33 +-
 .../ofbiz/webapp/ftl/CsrfTokenAjaxTransform.java   |  75 +++++
 .../webapp/ftl/CsrfTokenPairNonAjaxTransform.java  |  76 +++++
 .../ofbiz/webapp/freemarkerTransforms.properties   |   2 +
 .../webtools/groovyScripts/entity/CheckDb.groovy   |   7 +-
 .../webtools/groovyScripts/entity/EntityRef.groovy |   6 +
 framework/webtools/template/entity/CheckDb.ftl     |  28 +-
 .../webtools/template/entity/EntityRefList.ftl     |   9 +-
 framework/webtools/template/entity/ViewGeneric.ftl |   5 +-
 .../webapp/webtools/WEB-INF/controller.xml         |   2 +-
 .../java/org/apache/ofbiz/widget/WidgetWorker.java |  14 +
 .../widget/renderer/macro/MacroFormRenderer.java   |  14 +-
 themes/bluelight/template/Header.ftl               |   6 +-
 .../common-theme/template/includes/ListLocales.ftl |   2 +-
 .../template/macro/CsvFormMacroLibrary.ftl         |   2 +-
 .../template/macro/FoFormMacroLibrary.ftl          |   2 +-
 .../template/macro/HtmlFormMacroLibrary.ftl        |   8 +-
 .../template/macro/TextFormMacroLibrary.ftl        |   2 +-
 .../template/macro/XlsFormMacroLibrary.ftl         |   2 +-
 .../template/macro/XmlFormMacroLibrary.ftl         |   2 +-
 .../webapp/common/js/util/OfbizUtil.js             |  12 +-
 themes/flatgrey/template/Header.ftl                |   6 +-
 themes/rainbowstone/template/includes/Header.ftl   |   4 +
 .../rainbowstone/template/includes/TopAppBar.ftl   |   2 +-
 themes/tomahawk/template/AppBarClose.ftl           |   2 +-
 themes/tomahawk/template/Header.ftl                |   4 +
 41 files changed, 1179 insertions(+), 60 deletions(-)

diff --git a/applications/humanres/template/category/CategoryTree.ftl 
b/applications/humanres/template/category/CategoryTree.ftl
index 10a08ac..f14bbfc 100644
--- a/applications/humanres/template/category/CategoryTree.ftl
+++ b/applications/humanres/template/category/CategoryTree.ftl
@@ -61,18 +61,18 @@ var rawdata = [
         "plugins" : [ "themes", "json_data","ui" ,"cookies", "types", "crrm", 
"contextmenu"],
             "json_data" : {
                 "data" : rawdata,
-                          "ajax" : { "url" : 
"<@ofbizUrl>getHRChild</@ofbizUrl>", "type" : "POST",
-                          "data" : function (n) {
-                            return { 
+                "ajax" : { "url" : "<@ofbizUrl>getHRChild</@ofbizUrl>", "type" 
: "POST",
+                    "data" : function (n) {
+                            return {
                                 "partyId" : n.attr ? 
n.attr("id").replace("node_","") : 1 ,
                                 "additionParam" : "','category" ,
                                 "hrefString" : "viewprofile?partyId=" ,
                                 "onclickFunction" : "callDocument"
-                        }; 
+                        };
                     },
-                              success : function(data) {
-                                  return data.hrTree;
-                              }
+                    success : function(data) {
+                        return data.hrTree;
+                    }
                 }
             },
             "types" : {
@@ -92,7 +92,7 @@ var rawdata = [
   }
   
   function callDocument(id,type) {
-    window.location = "viewprofile?partyId=" + id;
+    window.location = "viewprofile?partyId=" + id + 
"&<@csrfTokenPair>viewprofile</@csrfTokenPair>";
   }
   
   function callEmplDocument(id,type) {
diff --git 
a/applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/CatalogAltUrlSeoTransform.java
 
b/applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/CatalogAltUrlSeoTransform.java
index b421681..653067b 100644
--- 
a/applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/CatalogAltUrlSeoTransform.java
+++ 
b/applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/CatalogAltUrlSeoTransform.java
@@ -25,12 +25,14 @@ import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.apache.ofbiz.security.CsrfUtil;
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.base.util.template.FreeMarkerWorker;
 import org.apache.ofbiz.entity.Delegator;
 import org.apache.ofbiz.entity.GenericEntityException;
 import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.entity.util.EntityQuery;
 import org.apache.ofbiz.entity.util.EntityUtilProperties;
 import org.apache.ofbiz.product.category.CatalogUrlFilter;
 import org.apache.ofbiz.product.category.CategoryContentWrapper;
@@ -48,7 +50,6 @@ import freemarker.template.SimpleNumber;
 import freemarker.template.SimpleScalar;
 import freemarker.template.TemplateModelException;
 import freemarker.template.TemplateTransformModel;
-import org.apache.ofbiz.entity.util.EntityQuery;
 
 public class CatalogAltUrlSeoTransform implements TemplateTransformModel {
     public final static String module = CatalogUrlSeoTransform.class.getName();
@@ -129,6 +130,11 @@ public class CatalogAltUrlSeoTransform implements 
TemplateTransformModel {
                                 url = 
CatalogUrlFilter.makeCategoryUrl(request, previousCategoryId, 
productCategoryId, productId, viewSize, viewIndex, viewSort, searchString);
                             }
                         }
+
+                        // add / update csrf token to link when required
+                        String tokenValue = 
CsrfUtil.generateTokenForNonAjax(request, "product");
+                        url = CsrfUtil.addOrUpdateTokenInUrl(url, tokenValue);
+
                         // make the link
                         if (fullPath) {
                             try {
diff --git 
a/applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/UrlRegexpTransform.java
 
b/applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/UrlRegexpTransform.java
index 48ac9b3..642d25f 100644
--- 
a/applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/UrlRegexpTransform.java
+++ 
b/applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/UrlRegexpTransform.java
@@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
 import org.apache.ofbiz.base.component.ComponentConfig;
+import org.apache.ofbiz.security.CsrfUtil;
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.template.FreeMarkerWorker;
 import org.apache.ofbiz.entity.Delegator;
@@ -134,8 +135,16 @@ public class UrlRegexpTransform implements 
TemplateTransformModel {
                         }
 
                         RequestHandler rh = RequestHandler.from(request);
-                        String link = rh.makeLink(request, response, 
buf.toString(), fullPath, secure || request.isSecure() , encode, controlPath);
-                        out.write(seoUrl(link, userLogin == null));
+                        String seoUrl = seoUrl(rh.makeLink(request, response, 
buf.toString(), fullPath,
+                                secure || request.isSecure(), encode, 
controlPath), userLogin == null);
+                        String requestURI = buf.toString();
+
+                        // add / update csrf token to link when required
+                        String tokenValue = 
CsrfUtil.generateTokenForNonAjax(request,
+                                controlPath + (requestURI.startsWith("/") ? 
requestURI : "/"+requestURI));
+                        seoUrl = CsrfUtil.addOrUpdateTokenInUrl(seoUrl, 
tokenValue);
+
+                        out.write(seoUrl);
                     } else if (!webSiteId.isEmpty()) {
                         Delegator delegator = 
FreeMarkerWorker.unwrap(env.getVariable("delegator"));
                         if (delegator == null) {
diff --git a/applications/product/template/category/CategoryTree.ftl 
b/applications/product/template/category/CategoryTree.ftl
index dce62c7..dd4ca21 100644
--- a/applications/product/template/category/CategoryTree.ftl
+++ b/applications/product/template/category/CategoryTree.ftl
@@ -65,7 +65,7 @@ var rawdata = [
             "plugins" : [ "themes", "json_data","ui" ,"cookies", "types"],
             "json_data" : {
                 "data" : rawdata,
-                "ajax" : { "url" : "<@ofbizUrl>getChild</@ofbizUrl>",
+                "ajax" : { "url" : "getChild",
                            "type" : "POST",
                            "data" : function (n) {
                                         return {
diff --git 
a/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java 
b/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java
index 2135444..aa42d61 100644
--- a/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java
+++ b/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java
@@ -77,7 +77,8 @@ public class CommonEvents {
         "thisRequestUri",
         "org.apache.tomcat.util.net.secure_protocol_version",
         "userLogin",
-        "impersonateLogin"
+        "impersonateLogin",
+        "requestMapMap" // requestMapMap is used by CSRFUtil
     };
 
     /** Simple event to set the users per-session locale setting. The user's 
locale
diff --git a/framework/common/webcommon/WEB-INF/common-controller.xml 
b/framework/common/webcommon/WEB-INF/common-controller.xml
index 80407c6..6526111 100644
--- a/framework/common/webcommon/WEB-INF/common-controller.xml
+++ b/framework/common/webcommon/WEB-INF/common-controller.xml
@@ -75,7 +75,7 @@ under the License.
         <response name="error" type="view" value="login"/>
     </request-map>
     <request-map uri="logout">
-        <security https="true" auth="true"/>
+        <security https="true" auth="true" csrf-token="false"/>
         <event type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" 
invoke="logout"/>
         <response name="success" type="request-redirect" value="main"/>
         <response name="error" type="view" value="main"/>
@@ -237,7 +237,8 @@ under the License.
     <!--========================== AJAX events =====================-->
     <!-- Get states related to a country -->
     <request-map uri="getAssociatedStateList">
-        <security https="true" auth="false"/>
+        <!-- depended on by ecommerce during checkout, so set the csrf-token 
to false -->
+        <security https="true" auth="false" csrf-token="false"/>
         <event type="service" invoke="getAssociatedStateList"/>
         <response name="success" type="request" value="json"/>
         <response name="error" type="request" value="json"/>
@@ -317,7 +318,7 @@ under the License.
 
     <!-- Set TimeZone from user's browser -->
     <!-- XXX The auth setting is inconsistent with the one in the service for 
a good reason, see OFBIZ-10471 for an explanation -->
-    <request-map uri="SetTimeZoneFromBrowser">
+    <request-map uri="SetTimeZoneFromBrowser" method="post">
         <security https="false" auth="false"/>
         <event type="service" invoke="SetTimeZoneFromBrowser"/>
         <response name="success" type="request" value="json"/>
diff --git a/framework/security/config/security.properties 
b/framework/security/config/security.properties
index 5a44fe2..55c2b6a 100644
--- a/framework/security/config/security.properties
+++ b/framework/security/config/security.properties
@@ -1,4 +1,4 @@
-###############################################################################
+##############################################################################
 # 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
@@ -149,5 +149,24 @@ security.jwt.token.expireTime=1800
 # -- To make this work you also have to configure a secret key with 
security.token.key
 security.internal.sso.enabled=false
 
-# -- The secret key for the JWT token signature. Read Passwords and JWT (JSON 
Web Tokens) usage documentation to choose the way you want to store this key 
+# -- The secret key for the JWT token signature. Read Passwords and JWT (JSON 
Web Tokens) usage documentation to choose the way you want to store this key
 security.token.key=security.token.key
+
+# -- The cache size for the Tokens Maps that stores the CSRF tokens. 
+# -- RemoveEldestEntry is used when it's get above csrf.cache.size
+# -- Default is 5000
+# -- TODO: separate tokenMap from partyTokenMap
+csrf.cache.size=
+
+# -- Parameter name for CSRF token. Default is "csrf" if not specified
+csrf.tokenName.nonAjax=
+
+# -- The csrf.entity.request.limit is used to show how to avoid cluttering the 
Tokens Maps cache with URIs starting with "entity/" 
+# -- It can be useful with large Database contents, ie with a large numbers of 
tuples, like "entity/edit/Agreement/10000, etc.
+# -- The same principle can be extended to other cases similar to "entity/" 
URIs (harcoded or using similar properties).
+# -- Default is 3
+csrf.entity.request.limit=
+
+# csrf defense strategy. Default is 
org.apache.ofbiz.security.CsrfDefenseStrategy if not specified.
+# use org.apache.ofbiz.security.NoCsrfDefenseStrategy to disable CSRF check 
totally.
+csrf.defense.strategy=
diff --git 
a/framework/security/src/main/java/org/apache/ofbiz/security/CsrfDefenseStrategy.java
 
b/framework/security/src/main/java/org/apache/ofbiz/security/CsrfDefenseStrategy.java
new file mode 100644
index 0000000..5b72990
--- /dev/null
+++ 
b/framework/security/src/main/java/org/apache/ofbiz/security/CsrfDefenseStrategy.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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.ofbiz.security;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.UtilProperties;
+import 
org.apache.ofbiz.webapp.control.RequestHandlerExceptionAllowExternalRequests;
+
+public class CsrfDefenseStrategy implements ICsrfDefenseStrategy {
+
+    public static final String module = CsrfDefenseStrategy.class.getName();
+    private static SecureRandom secureRandom = null;
+    private static final String prng = "SHA1PRNG";
+    private static final String CHARSET = 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+    private static int csrfEntityErequestLimit =  (int) 
Long.parseLong(UtilProperties.getPropertyValue("security", 
"csrf.entity.request.limit", "3"));
+
+    static{
+        try {
+            secureRandom = SecureRandom.getInstance(prng);
+        } catch (NoSuchAlgorithmException e) {
+            Debug.logError(e, module);
+        }
+    }
+
+    @Override
+    public String generateToken() {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 1; i < 12 + 1; i++) {
+            int index = secureRandom.nextInt(CHARSET.length());
+            char c = CHARSET.charAt(index);
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public int maxSubFolderInRequestUrlForTokenMapLookup(String requestUri){
+        if (requestUri.startsWith("entity/")){
+            return csrfEntityErequestLimit;
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean modifySecurityCsrfToken(String requestUri, String 
requestMapMethod, String securityCsrfToken) {
+        // main request URI is exempted from CSRF token check
+        if (requestUri.equals("main")) {
+            return false;
+        } else {
+            return !"false".equals(securityCsrfToken);
+        }
+    }
+
+
+    @Override
+    public boolean keepTokenAfterUse(String requestUri, String requestMethod) {
+        // to allow back and forth browser buttons to work,
+        // token value is unchanged when request.getMethod is GET
+        if ("GET".equals(requestMethod)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void invalidTokenResponse(String requestUri, HttpServletRequest 
request) throws RequestHandlerExceptionAllowExternalRequests {
+        request.setAttribute("_ERROR_MESSAGE_",
+                "Invalid or missing CSRF token to path '" + 
request.getPathInfo() + "'. Click <a href='"
+                        + request.getContextPath() + "'>here</a> to 
continue.");
+        throw new RequestHandlerExceptionAllowExternalRequests();
+    }
+}
diff --git 
a/framework/security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java 
b/framework/security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java
new file mode 100644
index 0000000..eaf5635
--- /dev/null
+++ b/framework/security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * 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.ofbiz.security;
+
+import java.net.MalformedURLException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.core.MultivaluedHashMap;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.cxf.jaxrs.model.URITemplate;
+import org.apache.ofbiz.base.component.ComponentConfig;
+import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.UtilGenerics;
+import org.apache.ofbiz.base.util.UtilProperties;
+import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.webapp.control.ConfigXMLReader;
+import org.apache.ofbiz.webapp.control.RequestHandler;
+import org.apache.ofbiz.webapp.control.RequestHandlerException;
+import 
org.apache.ofbiz.webapp.control.RequestHandlerExceptionAllowExternalRequests;
+import org.apache.ofbiz.webapp.control.WebAppConfigurationException;
+
+public class CsrfUtil {
+
+    public static final String module = CsrfUtil.class.getName();
+    public static String tokenNameNonAjax = 
UtilProperties.getPropertyValue("security", "csrf.tokenName.nonAjax", "csrf");
+    public static ICsrfDefenseStrategy strategy;
+    private static int cacheSize =  (int) 
Long.parseLong(UtilProperties.getPropertyValue("security", "csrf.cache.size", 
"5000"));
+    private static LinkedHashMap<String, Map<String, Map<String, String>>> 
csrfTokenCache = new LinkedHashMap<String, Map<String, Map<String, String>>>() {
+        private static final long serialVersionUID = 1L;
+        protected boolean removeEldestEntry(Map.Entry<String, Map<String, 
Map<String, String>>> eldest) {
+            return size() > cacheSize; // TODO use also csrf.cache.size here?
+        }
+    };
+
+    private CsrfUtil() {
+    }
+
+    static {
+        try {
+            String className = UtilProperties.getPropertyValue("security", 
"csrf.defense.strategy", CsrfDefenseStrategy.class.getCanonicalName());
+            Class<?> c = Class.forName(className);
+            strategy = (ICsrfDefenseStrategy)c.newInstance();
+        } catch (Exception e){
+            Debug.logError(e, module);
+            strategy = new CsrfDefenseStrategy();
+        }
+    }
+
+    public static Map<String, String> getTokenMap(HttpServletRequest request, 
String targetContextPath) {
+        
+        HttpSession session = request.getSession();
+        GenericValue userLogin = (GenericValue) 
session.getAttribute("userLogin");
+        String partyId = null;
+        if (userLogin != null && userLogin.get("partyId") != null) {
+            partyId = userLogin.getString("partyId");
+        }
+
+        Map<String, String> tokenMap = null;
+        if (UtilValidate.isNotEmpty(partyId)) {
+            Map<String, Map<String, String>> partyTokenMap = 
csrfTokenCache.get(partyId);
+            if (partyTokenMap == null) {
+                partyTokenMap = new HashMap<String, Map<String, String>>();
+                csrfTokenCache.put(partyId, partyTokenMap);
+            }
+
+            tokenMap = partyTokenMap.get(targetContextPath);
+            if (tokenMap == null) {
+                tokenMap = new LinkedHashMap<String, String>() {
+                    private static final long serialVersionUID = 1L;
+                    protected boolean removeEldestEntry(Map.Entry<String, 
String> eldest) {
+                        return size() > cacheSize;
+                    }
+                };
+                partyTokenMap.put(targetContextPath, tokenMap);
+            }
+        } else {
+            tokenMap = UtilGenerics.cast(session.getAttribute("CSRF-Token"));
+            if (tokenMap == null) {
+                tokenMap = new LinkedHashMap<String, String>() {
+                    private static final long serialVersionUID = 1L;
+                    protected boolean removeEldestEntry(Map.Entry<String, 
String> eldest) {
+                        return size() > cacheSize;
+                    }
+                };
+                session.setAttribute("CSRF-Token", tokenMap);
+            }
+        }
+        return tokenMap;
+    }
+
+    private static String generateToken() {
+        return strategy.generateToken();
+    }
+
+    /**
+     * Reduce number of subfolder from request uri, if needed, before using it 
to generate CSRF token.
+     * @param requestUri
+     * @return
+     */
+    static String getRequestUriWithSubFolderLimit(String requestUri){
+        int limit = 
CsrfUtil.strategy.maxSubFolderInRequestUrlForTokenMapLookup(requestUri);
+        if (limit<1){
+            return requestUri;
+        }
+        while(StringUtils.countMatches(requestUri, "/")+1>limit){
+            requestUri = requestUri.substring(0, requestUri.lastIndexOf("/"));
+        }
+        return requestUri;
+    }
+
+    static String getRequestUriFromPath(String pathOrRequestUri){
+        String requestUri = pathOrRequestUri;
+        // remove any query string
+        if (requestUri.contains("?")) {
+            // e.g. "/viewprofile?partyId=Company" to "/viewprofile"
+            requestUri = requestUri.substring(0, requestUri.indexOf("?"));
+        }
+        String controlServletPart = "/control/";
+        if (requestUri.contains(controlServletPart)) {
+            // e.g. "/partymgr/control/viewprofile" to "viewprofile"
+            requestUri = 
requestUri.substring(requestUri.indexOf(controlServletPart) + 
controlServletPart.length());
+        }
+        if (requestUri.startsWith("/")) {
+            // e.g. "/viewprofile" to "viewprofile"
+            requestUri = requestUri.substring(1);
+        }
+        if (requestUri.contains("#")){
+            // e.g. "view/entityref_main#org.apache.ofbiz.accounting.budget" 
to "view/entityref_main"
+            requestUri = requestUri.substring(0, requestUri.indexOf("#"));
+        }
+        return requestUri;
+    }
+
+    /**
+     * Generate CSRF token for non-ajax request if required and add it as key 
to token map in session When token map
+     * size limit is reached, the eldest entry will be deleted each time a new 
entry is added.
+     * Token only generated for up to 3 subfolders in the path so 
'entity/find/Budget/0001' & 'entity/find/Budget/0002'
+     * should share the same CSRF token.
+     * 
+     * @param request
+     * @param pathOrRequestUri
+     * @return csrf token
+     */
+    public static String generateTokenForNonAjax(HttpServletRequest request, 
String pathOrRequestUri) {
+        if (UtilValidate.isEmpty(pathOrRequestUri)
+                || pathOrRequestUri.startsWith("javascript")
+                || pathOrRequestUri.startsWith("#") ) {
+            return "";
+        }
+        
+        if (pathOrRequestUri.contains("&#x2f;")) {
+            pathOrRequestUri = pathOrRequestUri.replaceAll("&#x2f;", "/");
+        }
+
+        String requestUri = 
getRequestUriWithSubFolderLimit(getRequestUriFromPath(pathOrRequestUri));
+        
+        Map<String, String> tokenMap = null;
+
+        ConfigXMLReader.RequestMap requestMap = null;
+        // TODO when  OFBIZ-11354 will be done this will need to be removed 
even if it should be OK as is
+        if (pathOrRequestUri.contains("/control/")) { 
+            tokenMap = getTokenMap(request, "/" + 
RequestHandler.getRequestUri(pathOrRequestUri));
+            requestMap = findRequestMap(pathOrRequestUri);
+        } else {
+            tokenMap = getTokenMap(request, request.getContextPath());
+            Map<String, ConfigXMLReader.RequestMap> requestMapMap = 
UtilGenerics
+                    .cast(request.getAttribute("requestMapMap"));
+            requestMap = findRequestMap(requestMapMap, pathOrRequestUri);
+        }
+        if (requestMap == null) {
+            Debug.logError("Cannot find the corresponding request map for 
path: " + pathOrRequestUri, module);
+        }
+        String tokenValue = "";
+        if (requestMap != null && requestMap.securityCsrfToken) {
+            if (tokenMap.containsKey(requestUri)) {
+                tokenValue = tokenMap.get(requestUri);
+            } else {
+                tokenValue = generateToken();
+                tokenMap.put(requestUri, tokenValue);
+            }
+        }
+        return tokenValue;
+    }
+
+    static ConfigXMLReader.RequestMap findRequestMap(String 
_urlWithControlPath){
+
+        String requestUri = getRequestUriFromPath(_urlWithControlPath);
+
+        List<ComponentConfig.WebappInfo> webappInfos = 
ComponentConfig.getAllWebappResourceInfos().stream()
+                .filter(line -> 
line.contextRoot.contains(RequestHandler.getRequestUri(_urlWithControlPath)))
+                .collect(Collectors.toList());
+
+        ConfigXMLReader.RequestMap requestMap = null;
+        if (UtilValidate.isNotEmpty(webappInfos)) {
+            try {
+                if (StringUtils.countMatches(requestUri, "/")==1){
+                    requestMap = 
ConfigXMLReader.getControllerConfig(webappInfos.get(0)).getRequestMapMap()
+                            .get(requestUri.substring(0, 
requestUri.indexOf("/")));
+                } else {
+                    requestMap = 
ConfigXMLReader.getControllerConfig(webappInfos.get(0)).getRequestMapMap()
+                            .get(requestUri);
+                }
+            } catch (WebAppConfigurationException | MalformedURLException e) {
+                Debug.logError(e, module);
+            }
+        }
+        return requestMap;
+    }
+
+    static ConfigXMLReader.RequestMap findRequestMap(Map<String, 
ConfigXMLReader.RequestMap> requestMapMap,
+            String _urlWithoutControlPath) {
+        String path = _urlWithoutControlPath;
+        if (_urlWithoutControlPath.startsWith("/")) {
+            path = _urlWithoutControlPath.substring(1);
+        }
+        int charPos = path.indexOf("?");
+        if (charPos != -1) {
+            path = path.substring(0, charPos);
+        }
+        MultivaluedHashMap<String, String> vars = new MultivaluedHashMap<>();
+        for (Map.Entry<String, ConfigXMLReader.RequestMap> entry : 
requestMapMap.entrySet()) {
+            URITemplate uriTemplate = 
URITemplate.createExactTemplate(entry.getKey());
+            // Check if current path the URI template exactly.
+            if (uriTemplate.match(path, vars) && 
vars.getFirst(URITemplate.FINAL_MATCH_GROUP).equals("/")) {
+                return entry.getValue();
+            }
+        }
+        // the path could be request uri with orderride
+        if (path.contains("/")) {
+            return requestMapMap.get(path.substring(0, path.indexOf("/")));
+        }
+        return null;
+    }
+
+    /**
+     * generate csrf token for AJAX and add it as value to token cache
+     * 
+     * @param request
+     * @return csrf token
+     */
+    public static String generateTokenForAjax(HttpServletRequest request) {
+        HttpSession session = request.getSession();
+        String tokenValue = (String) session.getAttribute("X-CSRF-Token");
+        if (tokenValue == null) {
+            tokenValue = generateToken();
+            session.setAttribute("X-CSRF-Token", tokenValue);
+        }
+        return tokenValue;
+    }
+
+    /**
+     * get csrf token for AJAX
+     * 
+     * @param session
+     * @return csrf token
+     */
+    public static String getTokenForAjax(HttpSession session) {
+        return (String) session.getAttribute("X-CSRF-Token");
+    }
+
+    public static String addOrUpdateTokenInUrl(String link, String csrfToken) {
+        if (link.contains(CsrfUtil.tokenNameNonAjax)) {
+            return 
link.replaceFirst("\\b"+CsrfUtil.tokenNameNonAjax+"=.*?(&|$)", 
CsrfUtil.tokenNameNonAjax+"=" + csrfToken + "$1");
+        } else if (!"".equals(csrfToken)) {
+            if (link.contains("?")) {
+                return link + "&"+CsrfUtil.tokenNameNonAjax+"=" + csrfToken;
+            } else {
+                return link + "?"+CsrfUtil.tokenNameNonAjax+"=" + csrfToken;
+            }
+        }
+        return link;
+    }
+
+    public static String addOrUpdateTokenInQueryString(String link, String 
csrfToken) {
+        if (UtilValidate.isNotEmpty(link)) {
+            if (link.contains(CsrfUtil.tokenNameNonAjax)) {
+                return 
link.replaceFirst("\\b"+CsrfUtil.tokenNameNonAjax+"=.*?(&|$)", 
CsrfUtil.tokenNameNonAjax+"=" + csrfToken + "$1");
+            } else {
+                if (UtilValidate.isNotEmpty(csrfToken)) {
+                    return link + "&"+CsrfUtil.tokenNameNonAjax+"=" + 
csrfToken;
+                } else {
+                    return link;
+                }
+            }
+        } else {
+            return CsrfUtil.tokenNameNonAjax+"=" + csrfToken;
+        }
+    }
+
+    public static void checkToken(HttpServletRequest request, String _path)
+            throws RequestHandlerException, 
RequestHandlerExceptionAllowExternalRequests {
+        String path = _path;
+        if (_path.startsWith("/")) {
+            path = _path.substring(1);
+        }
+        if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With")) && 
!"GET".equals(request.getMethod())) {
+            String csrfToken = request.getHeader("X-CSRF-Token");
+            HttpSession session = request.getSession();
+            if ((UtilValidate.isEmpty(csrfToken) || 
!csrfToken.equals(CsrfUtil.getTokenForAjax(session)))
+                    && 
!"/SetTimeZoneFromBrowser".equals(request.getPathInfo())) { // TODO maybe this 
can be improved...
+                throw new RequestHandlerException(
+                        "Invalid or missing CSRF token for AJAX call to path 
'" + request.getPathInfo() + "'");
+            }
+        } else {
+            Map<String, String> tokenMap = CsrfUtil.getTokenMap(request, 
request.getContextPath());
+            String csrfToken = request.getParameter(CsrfUtil.tokenNameNonAjax);
+            String limitPath = getRequestUriWithSubFolderLimit(path);
+            if (UtilValidate.isNotEmpty(csrfToken) && 
tokenMap.containsKey(limitPath)
+                    && csrfToken.equals(tokenMap.get(limitPath))) {
+                if 
(!CsrfUtil.strategy.keepTokenAfterUse(path,request.getMethod())) {
+                    tokenMap.remove(limitPath);
+                }
+            } else {
+                CsrfUtil.strategy.invalidTokenResponse(path, request);
+            }
+        }
+    }
+
+    public static void cleanupTokenMap(HttpSession session) {
+        GenericValue userLogin = (GenericValue) 
session.getAttribute("userLogin");
+        String partyId = null;
+        if (userLogin != null && userLogin.get("partyId") != null) {
+            partyId = userLogin.getString("partyId");
+            Map<String, Map<String, String>> partyTokenMap = 
csrfTokenCache.get(partyId);
+            if (partyTokenMap != null) {
+                String contextPath = 
session.getServletContext().getContextPath();
+                partyTokenMap.remove(contextPath);
+                if (partyTokenMap.isEmpty()) {
+                    csrfTokenCache.remove(partyId);
+                }
+            }
+        }
+    }
+}
diff --git 
a/framework/security/src/main/java/org/apache/ofbiz/security/ICsrfDefenseStrategy.java
 
b/framework/security/src/main/java/org/apache/ofbiz/security/ICsrfDefenseStrategy.java
new file mode 100644
index 0000000..322afb5
--- /dev/null
+++ 
b/framework/security/src/main/java/org/apache/ofbiz/security/ICsrfDefenseStrategy.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.ofbiz.security;
+
+import javax.servlet.http.HttpServletRequest;
+
+import 
org.apache.ofbiz.webapp.control.RequestHandlerExceptionAllowExternalRequests;
+
+public interface ICsrfDefenseStrategy {
+
+    String generateToken();
+
+    /**
+     * Limit the number of subfolders in request uri to reduce the number of 
CSRF tokens needed.
+     * @param requestUri
+     * @return
+     */
+    int maxSubFolderInRequestUrlForTokenMapLookup(String requestUri);
+
+    /**
+     * Override security csrf-token value in request map
+     * @param requestUri
+     * @param requestMapMethod  get, post or all
+     * @param securityCsrfToken
+     * @return
+     */
+    boolean modifySecurityCsrfToken(String requestUri, String 
requestMapMethod, String securityCsrfToken);
+
+    /**
+     * Whether to reuse the token after it is consumed
+     * @param requestUri
+     * @param requestMethod GET, POST, or PUT
+     * @return
+     */
+    boolean keepTokenAfterUse(String requestUri, String requestMethod);
+
+    void invalidTokenResponse(String requestUri, HttpServletRequest request) 
throws RequestHandlerExceptionAllowExternalRequests;
+
+}
\ No newline at end of file
diff --git 
a/framework/security/src/main/java/org/apache/ofbiz/security/NoCsrfDefenseStrategy.java
 
b/framework/security/src/main/java/org/apache/ofbiz/security/NoCsrfDefenseStrategy.java
new file mode 100644
index 0000000..279310c
--- /dev/null
+++ 
b/framework/security/src/main/java/org/apache/ofbiz/security/NoCsrfDefenseStrategy.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.ofbiz.security;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class NoCsrfDefenseStrategy implements ICsrfDefenseStrategy {
+
+    @Override
+    public String generateToken() {
+        return null;
+    }
+
+    @Override
+    public int maxSubFolderInRequestUrlForTokenMapLookup(String requestUri){
+        return 0;
+    }
+
+    @Override
+    public boolean modifySecurityCsrfToken(String requestUri, String 
requestMapMethod, String securityCsrfToken) {
+        // all SecurityCsrfToken checks in request maps are read as false
+        return false;
+    }
+
+    @Override
+    public boolean keepTokenAfterUse(String requestUri, String requestMethod) {
+        return false;
+    }
+
+    @Override
+    public void invalidTokenResponse(String requestUri, HttpServletRequest 
request) {
+
+    }
+}
\ No newline at end of file
diff --git 
a/framework/security/src/test/java/org/apache/ofbiz/security/CsrfUtilTests.java 
b/framework/security/src/test/java/org/apache/ofbiz/security/CsrfUtilTests.java
new file mode 100644
index 0000000..53d0096
--- /dev/null
+++ 
b/framework/security/src/test/java/org/apache/ofbiz/security/CsrfUtilTests.java
@@ -0,0 +1,264 @@
+/*
+ * 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.ofbiz.security;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.webapp.control.ConfigXMLReader;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class CsrfUtilTests {
+
+    @Test
+    public void testGetTokenMap(){
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        HttpSession session = mock(HttpSession.class);
+        when(request.getSession()).thenReturn(session);
+
+        // prepare the token map to be retrieved from session
+        Map<String,String> tokenMap = new LinkedHashMap<String, String>();
+        tokenMap.put("uri_1","abcd");
+        when(session.getAttribute("CSRF-Token")).thenReturn(tokenMap);
+
+        // without userLogin in session, test token map is retrieved from 
session
+        Map<String, String> resultMap = CsrfUtil.getTokenMap(request, "");
+        assertEquals("abcd", resultMap.get("uri_1"));
+
+        // add userLogin to session
+        GenericValue userLogin = mock(GenericValue.class);
+        when(userLogin.get("partyId")).thenReturn("10000");
+        when(userLogin.getString("partyId")).thenReturn("10000");
+        when(session.getAttribute("userLogin")).thenReturn(userLogin);
+
+        // with userLogin in session, test token map is not retrieved from 
session
+        resultMap = CsrfUtil.getTokenMap(request, "/partymgr");
+        assertNull(resultMap.get("uri_1"));
+
+    }
+
+    @Test
+    public void testGetRequestUriWithSubFolderLimit(){
+        CsrfUtil.strategy = new CsrfDefenseStrategy();
+
+        // limit only when request uri starts with 'entity'
+        String limitRequestUri = 
CsrfUtil.getRequestUriWithSubFolderLimit("entity/find/Budget/0002");
+        assertEquals("entity/find/Budget", limitRequestUri);
+
+        limitRequestUri = CsrfUtil.getRequestUriWithSubFolderLimit("a/b/c/d");
+        assertEquals("a/b/c/d", limitRequestUri);
+    }
+
+    @Test
+    public void testGetRequestUriFromPath(){
+        String requestUri = 
CsrfUtil.getRequestUriFromPath("/viewprofile?partyId=Company");
+        assertEquals("viewprofile", requestUri);
+
+        requestUri = 
CsrfUtil.getRequestUriFromPath("/partymgr/control/viewprofile");
+        assertEquals("viewprofile", requestUri);
+
+        requestUri = 
CsrfUtil.getRequestUriFromPath("view/entityref_main#org.apache.ofbiz.accounting.budget");
+        assertEquals("view/entityref_main", requestUri);
+    }
+
+
+    @Test
+    public void testGenerateTokenForNonAjax() throws 
ParserConfigurationException {
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        HttpSession session = mock(HttpSession.class);
+        when(request.getSession()).thenReturn(session);
+
+        // add userLogin to session
+        GenericValue userLogin = mock(GenericValue.class);
+        when(userLogin.get("partyId")).thenReturn("10000");
+        when(userLogin.getString("partyId")).thenReturn("10000");
+        when(session.getAttribute("userLogin")).thenReturn(userLogin);
+
+        String token = CsrfUtil.generateTokenForNonAjax(request, "");
+        assertEquals("", token);
+
+        token = CsrfUtil.generateTokenForNonAjax(request, "javascript:");
+        assertEquals("", token);
+
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = dbf.newDocumentBuilder();
+        Document doc = builder.newDocument();
+
+        Map<String, ConfigXMLReader.RequestMap> requestMapMap = new 
HashMap<>();
+        {
+            Element requestMapElement = doc.createElement("request-map");
+            requestMapElement.setAttribute("uri", "checkLogin");
+            ConfigXMLReader.RequestMap requestMap = new 
ConfigXMLReader.RequestMap(requestMapElement);
+            requestMapMap.put(requestMap.uri, requestMap);
+        }
+        {
+            Element requestMapElement = doc.createElement("request-map");
+            requestMapElement.setAttribute("uri", 
"entity/find/{entityName}/{pkValues: .*}");
+            ConfigXMLReader.RequestMap requestMap = new 
ConfigXMLReader.RequestMap(requestMapElement);
+            requestMapMap.put(requestMap.uri, requestMap);
+        }
+        when(request.getAttribute("requestMapMap")).thenReturn(requestMapMap);
+
+        token = CsrfUtil.generateTokenForNonAjax(request, "checkLogin");
+        assertNotEquals("", token);
+
+        CsrfUtil.strategy = new CsrfDefenseStrategy();
+
+        token = CsrfUtil.generateTokenForNonAjax(request, 
"entity/find/Budget/0001");
+        assertNotEquals("", token);
+
+        String token2 = CsrfUtil.generateTokenForNonAjax(request, 
"entity/find&#x2f;Budget/0001");
+        // test support for treating "&#x2f;" as "/"
+        assertEquals(token2, token);
+
+        token2 = CsrfUtil.generateTokenForNonAjax(request, 
"entity/find/Budget/0002");
+        // token only generated for up to 3 subfolders in the path
+        assertEquals(token2, token);
+    }
+
+    @Test
+    public void testFindRequestMapWithoutControlPath() throws 
ParserConfigurationException {
+
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = dbf.newDocumentBuilder();
+        Document doc = builder.newDocument();
+
+        Map<String, ConfigXMLReader.RequestMap> requestMapMap = new 
HashMap<>();
+        {
+            Element requestMapElement = doc.createElement("request-map");
+            requestMapElement.setAttribute("uri", "checkLogin");
+            ConfigXMLReader.RequestMap requestMap = new 
ConfigXMLReader.RequestMap(requestMapElement);
+            requestMapMap.put(requestMap.uri, requestMap);
+        }
+        // REST request like /entity/find/AccommodationClass
+        {
+            Element requestMapElement = doc.createElement("request-map");
+            requestMapElement.setAttribute("uri", "entity/find/{entityName}");
+            ConfigXMLReader.RequestMap requestMap = new 
ConfigXMLReader.RequestMap(requestMapElement);
+            requestMapMap.put(requestMap.uri, requestMap);
+        }
+        // View override like /view/ModelInduceFromDb
+        {
+            Element requestMapElement = doc.createElement("request-map");
+            requestMapElement.setAttribute("uri", "view");
+            ConfigXMLReader.RequestMap requestMap = new 
ConfigXMLReader.RequestMap(requestMapElement);
+            requestMapMap.put(requestMap.uri, requestMap);
+        }
+        {
+            Element requestMapElement = doc.createElement("request-map");
+            requestMapElement.setAttribute("uri", "ModelInduceFromDb");
+            ConfigXMLReader.RequestMap requestMap = new 
ConfigXMLReader.RequestMap(requestMapElement);
+            requestMapMap.put(requestMap.uri, requestMap);
+        }
+
+        // test usual request
+        ConfigXMLReader.RequestMap requestMap = 
CsrfUtil.findRequestMap(requestMapMap, "/checkLogin");
+        assertEquals(requestMap.uri, "checkLogin");
+
+        // test usual request
+        requestMap = CsrfUtil.findRequestMap(requestMapMap, "checkLogin");
+        assertEquals(requestMap.uri, "checkLogin");
+
+        // test REST request
+        requestMap = CsrfUtil.findRequestMap(requestMapMap, 
"/entity/find/AccommodationClass");
+        assertEquals(requestMap.uri, "entity/find/{entityName}");
+
+        // test view orderride
+        requestMap = CsrfUtil.findRequestMap(requestMapMap, 
"/view/ModelInduceFromDb");
+        assertEquals(requestMap.uri, "view");
+
+    }
+
+    @Test
+    public void testGenerateTokenForAjax() {
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        HttpSession session = mock(HttpSession.class);
+        when(request.getSession()).thenReturn(session);
+        when(session.getAttribute("X-CSRF-Token")).thenReturn("abcd");
+
+        String token = CsrfUtil.generateTokenForAjax(request);
+        assertEquals("abcd", token);
+    }
+
+    @Test
+    public void testGetTokenForAjax(){
+        HttpSession session = mock(HttpSession.class);
+        when(session.getAttribute("X-CSRF-Token")).thenReturn("abcd");
+
+        String token = CsrfUtil.getTokenForAjax(session);
+        assertEquals("abcd", token);
+    }
+
+    @Test
+    public void testAddOrUpdateTokenInUrl(){
+        CsrfUtil.tokenNameNonAjax = "csrfToken";
+
+        // test link without csrfToken
+        String url = 
CsrfUtil.addOrUpdateTokenInUrl("https://localhost:8443/catalog/control/login";, 
"abcd");
+        
assertEquals("https://localhost:8443/catalog/control/login?csrfToken=abcd";, 
url);
+
+        // test link with query string and without csrfToken
+        url = 
CsrfUtil.addOrUpdateTokenInUrl("https://localhost:8443/partymgr/control/EditCommunicationEvent?communicationEventId=10000";,
 "abcd");
+        
assertEquals("https://localhost:8443/partymgr/control/EditCommunicationEvent?communicationEventId=10000&csrfToken=abcd";,
 url);
+
+        // test link with csrfToken
+        url = 
CsrfUtil.addOrUpdateTokenInUrl("https://localhost:8443/catalog/control/login?csrfToken=abcd";,
 "efgh");
+        
assertEquals("https://localhost:8443/catalog/control/login?csrfToken=efgh";, 
url);
+
+        // test link with csrfToken amd empty csrfToken replacement
+        url = 
CsrfUtil.addOrUpdateTokenInUrl("https://localhost:8443/catalog/control/login?csrfToken=abcd";,
 "");
+        
assertEquals("https://localhost:8443/catalog/control/login?csrfToken=";, url);
+    }
+
+    @Test
+    public void testAddOrUpdateTokenInQueryString(){
+        CsrfUtil.tokenNameNonAjax = "csrfToken";
+
+        String queryString = CsrfUtil.addOrUpdateTokenInQueryString("", 
"abcd");
+        assertEquals(queryString, "csrfToken=abcd");
+
+        queryString = 
CsrfUtil.addOrUpdateTokenInQueryString("csrfToken=abcd&a=b", "efgh");
+        assertEquals(queryString, "csrfToken=efgh&a=b");
+
+        queryString = 
CsrfUtil.addOrUpdateTokenInQueryString("csrfToken=abcd&a=b", "");
+        assertEquals(queryString, "csrfToken=&a=b");
+
+        queryString = CsrfUtil.addOrUpdateTokenInQueryString("a=b", "abcd");
+        assertEquals(queryString, "a=b&csrfToken=abcd");
+
+        queryString = CsrfUtil.addOrUpdateTokenInQueryString("a=b", "");
+        assertEquals(queryString, "a=b");
+    }
+}
diff --git a/framework/webapp/dtd/site-conf.xsd 
b/framework/webapp/dtd/site-conf.xsd
index fc9a966..01d0046 100644
--- a/framework/webapp/dtd/site-conf.xsd
+++ b/framework/webapp/dtd/site-conf.xsd
@@ -305,6 +305,20 @@ under the License.
                 </xs:documentation>
             </xs:annotation>
         </xs:attribute>
+        <xs:attribute name="csrf-token" use="optional" default="">
+            <xs:annotation>
+                <xs:documentation>
+                    If true csrf token is expected. If false no csrf token 
check. Default to "".
+                </xs:documentation>
+            </xs:annotation>
+            <xs:simpleType>
+                <xs:restriction base="xs:token">
+                    <xs:enumeration value=""/>
+                    <xs:enumeration value="true"/>
+                    <xs:enumeration value="false"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
     </xs:attributeGroup>
     <xs:element name="metric">
         <xs:annotation>
diff --git 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
index 0802582..b542036 100644
--- 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
+++ 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
@@ -54,6 +54,7 @@ import org.apache.ofbiz.base.util.cache.UtilCache;
 import org.apache.ofbiz.base.util.collections.MapContext;
 import org.apache.ofbiz.base.util.collections.MultivaluedMapContext;
 import org.apache.ofbiz.base.util.collections.MultivaluedMapContextAdapter;
+import org.apache.ofbiz.security.CsrfUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -450,6 +451,7 @@ public class ConfigXMLReader {
         public Event event;
         public boolean securityHttps = true;
         public boolean securityAuth = false;
+        public boolean securityCsrfToken = true;
         public boolean securityCert = false;
         public boolean securityExternalView = true;
         public boolean securityDirectRequest = true;
@@ -481,6 +483,7 @@ public class ConfigXMLReader {
                 this.securityCert = 
"true".equals(securityElement.getAttribute("cert"));
                 this.securityExternalView = 
!"false".equals(securityElement.getAttribute("external-view"));
                 this.securityDirectRequest = 
!"false".equals(securityElement.getAttribute("direct-request"));
+                this.securityCsrfToken = 
CsrfUtil.strategy.modifySecurityCsrfToken(this.uri, this.method, 
securityElement.getAttribute("csrf-token"));
             }
             // Check for event
             Element eventElement = 
UtilXml.firstChildElement(requestMapElement, "event");
diff --git 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ControlEventListener.java
 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ControlEventListener.java
index 22fd632..54cb206 100644
--- 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ControlEventListener.java
+++ 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ControlEventListener.java
@@ -26,6 +26,7 @@ import javax.servlet.http.HttpSession;
 import javax.servlet.http.HttpSessionEvent;
 import javax.servlet.http.HttpSessionListener;
 
+import org.apache.ofbiz.security.CsrfUtil;
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.UtilDateTime;
 import org.apache.ofbiz.base.util.UtilGenerics;
@@ -71,6 +72,8 @@ public class ControlEventListener implements 
HttpSessionListener {
     public void sessionDestroyed(HttpSessionEvent event) {
         HttpSession session = event.getSession();
 
+        CsrfUtil.cleanupTokenMap(session);
+
         // Finalize the Visit
         boolean beganTransaction = false;
         try {
diff --git 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java
 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java
index 0e91bb1..1fe488a 100644
--- 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java
+++ 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java
@@ -45,6 +45,7 @@ import javax.ws.rs.core.MultivaluedHashMap;
 
 import org.apache.cxf.jaxrs.model.URITemplate;
 import org.apache.ofbiz.base.location.FlexibleLocation;
+import org.apache.ofbiz.security.CsrfUtil;
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.SSLUtil;
 import org.apache.ofbiz.base.util.StringUtil;
@@ -428,6 +429,13 @@ public class RequestHandler {
         if (Debug.verboseOn()) Debug.logVerbose("[Processing Request]: " + 
requestMap.uri + showSessionId(request), module);
         request.setAttribute("thisRequestUri", requestMap.uri); // store the 
actual request URI
 
+        // Store current requestMap map to be referred later when generating 
csrf token
+        request.setAttribute("requestMapMap", 
getControllerConfig().getRequestMapMap());
+
+        // Perform CSRF token check when request not on chain
+        if (chain==null && originalRequestMap.securityCsrfToken) {
+                CsrfUtil.checkToken(request, path);
+        }
 
         // Perform security check.
         if (requestMap.securityAuth) {
@@ -578,8 +586,13 @@ public class RequestHandler {
                 if (UtilValidate.isNotEmpty(queryString)) {
                     redirectTarget += "?" + queryString;
                 }
-                
-                callRedirect(makeLink(request, response, redirectTarget), 
response, request, ccfg.getStatusCode());
+                String link = makeLink(request, response, redirectTarget);
+
+                // add / update csrf token to link when required
+                String tokenValue = 
CsrfUtil.generateTokenForNonAjax(request,redirectTarget);
+                link = CsrfUtil.addOrUpdateTokenInUrl(link, tokenValue);
+
+                callRedirect(link, response, request, ccfg.getStatusCode());
                 return;
             }
         }
@@ -659,10 +672,22 @@ public class RequestHandler {
                 callRedirect(url + this.makeQueryString(request, 
nextRequestResponse), response, request, redirectSC);
             } else if ("request-redirect".equals(nextRequestResponse.type)) {
                 if (Debug.verboseOn()) 
Debug.logVerbose("[RequestHandler.doRequest]: Response is a Request redirect." 
+ showSessionId(request), module);
-                callRedirect(makeLinkWithQueryString(request, response, "/" + 
nextRequestResponse.value, nextRequestResponse), response, request, redirectSC);
+                String link = makeLinkWithQueryString(request, response, "/" + 
nextRequestResponse.value, nextRequestResponse);
+
+                // add / update csrf token to link when required
+                String tokenValue = CsrfUtil.generateTokenForNonAjax(request, 
nextRequestResponse.value);
+                link = CsrfUtil.addOrUpdateTokenInUrl(link, tokenValue);
+
+                callRedirect(link, response, request, redirectSC);
             } else if 
("request-redirect-noparam".equals(nextRequestResponse.type)) {
                 if (Debug.verboseOn()) 
Debug.logVerbose("[RequestHandler.doRequest]: Response is a Request redirect 
with no parameters." + showSessionId(request), module);
-                callRedirect(makeLink(request, response, 
nextRequestResponse.value), response, request, redirectSC);
+                String link = makeLink(request, response, 
nextRequestResponse.value);
+
+                // add token to link when required
+                String tokenValue = CsrfUtil.generateTokenForNonAjax(request, 
nextRequestResponse.value);
+                link = CsrfUtil.addOrUpdateTokenInUrl(link, tokenValue);
+
+                callRedirect(link, response, request, redirectSC);
             } else if ("view".equals(nextRequestResponse.type)) {
                 if (Debug.verboseOn()) 
Debug.logVerbose("[RequestHandler.doRequest]: Response is a view." + 
showSessionId(request), module);
 
diff --git 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/CsrfTokenAjaxTransform.java
 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/CsrfTokenAjaxTransform.java
new file mode 100644
index 0000000..6a2d89e
--- /dev/null
+++ 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/CsrfTokenAjaxTransform.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * 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.ofbiz.webapp.ftl;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.ofbiz.security.CsrfUtil;
+
+import freemarker.core.Environment;
+import freemarker.ext.beans.BeanModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateTransformModel;
+
+/**
+ * CsrfTokenAjaxTransform - Freemarker Transform for csrf token in Ajax call
+ */
+public class CsrfTokenAjaxTransform implements TemplateTransformModel {
+
+    public final static String module = CsrfTokenAjaxTransform.class.getName();
+
+    @Override
+    public Writer getWriter(Writer out, @SuppressWarnings("rawtypes") Map args)
+            throws TemplateModelException, IOException {
+
+        return new Writer(out) {
+
+            @Override
+            public void close() throws IOException {
+                try {
+                    Environment env = Environment.getCurrentEnvironment();
+                    BeanModel req = (BeanModel) env.getVariable("request");
+                    if (req != null) {
+                        HttpServletRequest request = (HttpServletRequest) 
req.getWrappedObject();
+                        String tokenValue = 
CsrfUtil.generateTokenForAjax(request);
+                        out.write(tokenValue);
+                    }
+                    return;
+                } catch (Exception e) {
+                    throw new IOException(e.getMessage());
+                }
+            }
+
+            @Override
+            public void flush() throws IOException {
+                out.flush();
+            }
+
+            @Override
+            public void write(char cbuf[], int off, int len) {
+
+            }
+        };
+
+    }
+}
diff --git 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/CsrfTokenPairNonAjaxTransform.java
 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/CsrfTokenPairNonAjaxTransform.java
new file mode 100644
index 0000000..d51bd61
--- /dev/null
+++ 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/CsrfTokenPairNonAjaxTransform.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * 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.ofbiz.webapp.ftl;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.ofbiz.security.CsrfUtil;
+
+import freemarker.core.Environment;
+import freemarker.ext.beans.BeanModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateTransformModel;
+
+/**
+ * CsrfTokenPairNonAjaxTransform - Freemarker Transform for csrf token in 
non-Ajax call
+ */
+public class CsrfTokenPairNonAjaxTransform implements TemplateTransformModel {
+
+    public final static String module = 
CsrfTokenPairNonAjaxTransform.class.getName();
+
+    @Override
+    public Writer getWriter(Writer out, @SuppressWarnings("rawtypes") Map args)
+            throws TemplateModelException, IOException {
+
+        final StringBuffer buf = new StringBuffer();
+
+        return new Writer(out) {
+
+            @Override
+            public void close() throws IOException {
+                try {
+                    Environment env = Environment.getCurrentEnvironment();
+                    BeanModel req = (BeanModel) env.getVariable("request");
+                    if (req != null) {
+                        HttpServletRequest request = (HttpServletRequest) 
req.getWrappedObject();
+                        String tokenValue = 
CsrfUtil.generateTokenForNonAjax(request, buf.toString());
+                        out.write(CsrfUtil.tokenNameNonAjax +"="+tokenValue);
+                    }
+                    return;
+                } catch (Exception e) {
+                    throw new IOException(e.getMessage());
+                }
+            }
+
+            @Override
+            public void write(char cbuf[], int off, int len) {
+                buf.append(cbuf, off, len);
+            }
+
+            @Override
+            public void flush() throws IOException {
+                out.flush();
+            }
+        };
+    }
+}
diff --git 
a/framework/webapp/src/main/resources/org/apache/ofbiz/webapp/freemarkerTransforms.properties
 
b/framework/webapp/src/main/resources/org/apache/ofbiz/webapp/freemarkerTransforms.properties
index 46f7979..65cf04e 100644
--- 
a/framework/webapp/src/main/resources/org/apache/ofbiz/webapp/freemarkerTransforms.properties
+++ 
b/framework/webapp/src/main/resources/org/apache/ofbiz/webapp/freemarkerTransforms.properties
@@ -29,3 +29,5 @@ ofbizNumber=org.apache.ofbiz.webapp.ftl.OfbizNumberTransform
 setRequestAttribute=org.apache.ofbiz.webapp.ftl.SetRequestAttributeMethod
 renderWrappedText=org.apache.ofbiz.webapp.ftl.RenderWrappedTextTransform
 setContextField=org.apache.ofbiz.webapp.ftl.SetContextFieldTransform
+csrfTokenAjax=org.apache.ofbiz.webapp.ftl.CsrfTokenAjaxTransform
+csrfTokenPair=org.apache.ofbiz.webapp.ftl.CsrfTokenPairNonAjaxTransform
diff --git a/framework/webtools/groovyScripts/entity/CheckDb.groovy 
b/framework/webtools/groovyScripts/entity/CheckDb.groovy
index fd822de..567714f 100644
--- a/framework/webtools/groovyScripts/entity/CheckDb.groovy
+++ b/framework/webtools/groovyScripts/entity/CheckDb.groovy
@@ -16,10 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import org.apache.ofbiz.entity.Delegator
-import org.apache.ofbiz.security.Security
+
+
 import org.apache.ofbiz.entity.jdbc.DatabaseUtil
-import org.apache.ofbiz.entity.model.ModelEntity
 
 controlPath = parameters._CONTROL_PATH_
 
@@ -114,7 +113,7 @@ if (security.hasPermission("ENTITY_MAINT", session)) {
         miter = messages.iterator()
         context.miters = miter
     }
-    context.encodeURLCheckDb = response.encodeURL(controlPath + 
"/view/checkdb")
+    context.checkDbURL = "view/checkdb"
     context.groupName = groupName ?: "org.apache.ofbiz"
     context.entityName = entityName ?: ""
 }
diff --git a/framework/webtools/groovyScripts/entity/EntityRef.groovy 
b/framework/webtools/groovyScripts/entity/EntityRef.groovy
index 17933db..279e448 100644
--- a/framework/webtools/groovyScripts/entity/EntityRef.groovy
+++ b/framework/webtools/groovyScripts/entity/EntityRef.groovy
@@ -16,6 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import org.apache.ofbiz.security.CsrfUtil;
+
 controlPath = parameters._CONTROL_PATH_
 list = "$controlPath/view/entityref_list"
 main = "$controlPath/view/entityref_main"
@@ -29,5 +31,9 @@ if (search) {
     list = "$list?forstatic=$forstatic"
     main = "$main?forstatic=$forstatic"
 }
+tokenList = CsrfUtil.generateTokenForNonAjax(request, "view/entityref_list")
+tokenMain = CsrfUtil.generateTokenForNonAjax(request, "view/entityref_main")
+list = CsrfUtil.addOrUpdateTokenInUrl(list, tokenList)
+main = CsrfUtil.addOrUpdateTokenInUrl(main, tokenMain)
 context.encodeUrlList = response.encodeURL(list)
 context.encodeUrlMain = response.encodeURL(main)
diff --git a/framework/webtools/template/entity/CheckDb.ftl 
b/framework/webtools/template/entity/CheckDb.ftl
index ac81459..91cf8d3 100644
--- a/framework/webtools/template/entity/CheckDb.ftl
+++ b/framework/webtools/template/entity/CheckDb.ftl
@@ -17,7 +17,7 @@ specific language governing permissions and limitations
 under the License.
 -->
 <h3>${uiLabelMap.WebtoolsCheckUpdateDatabase}</h3>
-<form class="basic-form" class="basic-form" method="post" 
action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -61,7 +61,7 @@ under the License.
    }
 </script>
 <h3>${uiLabelMap.WebtoolsRemoveAllTables}</h3>
-<form class="basic-form" class="basic-form" method="post" 
action="${encodeURLCheckDb}" name="TablesRemoveForm">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>" name="TablesRemoveForm">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -80,7 +80,7 @@ under the License.
       </tbody>
    </table>
 </form>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}" 
name="TableRemoveForm">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>" name="TableRemoveForm">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -107,7 +107,7 @@ under the License.
    </table>
 </form>
 <h3>${uiLabelMap.WebtoolsCreateRemoveAllPrimaryKeys}</h3>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -125,7 +125,7 @@ under the License.
       </tbody>
    </table>
 </form>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -143,7 +143,7 @@ under the License.
    </table>
 </form>
 <h3>${uiLabelMap.WebtoolsCreateRemovePrimaryKey}</h3>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -168,7 +168,7 @@ under the License.
       </tbody>
    </table>
 </form>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -197,7 +197,7 @@ under the License.
    </table>
 </form>
 <h3>${uiLabelMap.WebtoolsCreateRemoveAllDeclaredIndices}</h3>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -214,7 +214,7 @@ under the License.
       </tbody>
    </table>
 </form>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -232,7 +232,7 @@ under the License.
    </table>
 </form>
 <h3>${uiLabelMap.WebtoolsCreateRemoveAllForeignKeyIndices}</h3>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -249,7 +249,7 @@ under the License.
       </tbody>
    </table>
 </form>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -268,7 +268,7 @@ under the License.
 </form>
 <h3>${uiLabelMap.WebtoolsCreateRemoveAllForeignKeys}</h3>
 <p>${uiLabelMap.WebtoolsNoteForeighKeysMayAlsoBeCreated}</p>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -285,7 +285,7 @@ under the License.
       </tbody>
    </table>
 </form>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
@@ -303,7 +303,7 @@ under the License.
    </table>
 </form>
 <h3>${uiLabelMap.WebtoolsUpdateCharacterSetAndCollate}</h3>
-<form class="basic-form" method="post" action="${encodeURLCheckDb}">
+<form class="basic-form" method="post" 
action="<@ofbizUrl>${checkDbURL}</@ofbizUrl>">
    <table class="basic-table" cellspacing="0">
       <tbody>
          <tr>
diff --git a/framework/webtools/template/entity/EntityRefList.ftl 
b/framework/webtools/template/entity/EntityRefList.ftl
index 1ace17f..55e2387 100644
--- a/framework/webtools/template/entity/EntityRefList.ftl
+++ b/framework/webtools/template/entity/EntityRefList.ftl
@@ -1,3 +1,4 @@
+
 <#--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -54,9 +55,9 @@ under the License.
                 <div 
class="section-header">${uiLabelMap.WebtoolsEntityPackages}</div>
                 <#list packageNames as packageName>
                     <#if forstatic>
-                        <a 
href="<@ofbizUrl>view/entityref_main?forstatic=true#${packageName}</@ofbizUrl>" 
target="entityFrame">${packageName}</a><br />
+                        <a 
href="<@ofbizUrl>view/entityref_main?forstatic=true</@ofbizUrl>#${packageName}" 
target="entityFrame">${packageName}</a><br />
                     <#else>
-                        <a 
href="<@ofbizUrl>view/entityref_main#${packageName}</@ofbizUrl>" 
target="entityFrame">${packageName}</a><br />
+                        <a 
href="<@ofbizUrl>view/entityref_main</@ofbizUrl>#${packageName}" 
target="entityFrame">${packageName}</a><br />
                     </#if>
                 </#list>
             </#if>
@@ -65,9 +66,9 @@ under the License.
                 <div 
class="section-header">${uiLabelMap.WebtoolsEntitiesAlpha}</div>
                 <#list entitiesList as entity>
                     <#if forstatic>
-                        <a 
href="<@ofbizUrl>view/entityref_main?forstatic=true#${entity.entityName}</@ofbizUrl>"
 target="entityFrame">${entity.entityName}</a>
+                        <a 
href="<@ofbizUrl>view/entityref_main?forstatic=true</@ofbizUrl>#${entity.entityName}"
 target="entityFrame">${entity.entityName}</a>
                     <#else>
-                        <a 
href="<@ofbizUrl>view/entityref_main#${entity.entityName}${entity.url!}</@ofbizUrl>"
 target="entityFrame">${entity.entityName}</a>
+                        <a 
href="<@ofbizUrl>view/entityref_main</@ofbizUrl>#${entity.entityName}${entity.url!}"
 target="entityFrame">${entity.entityName}</a>
                     </#if>
                     <br />
                 </#list>
diff --git a/framework/webtools/template/entity/ViewGeneric.ftl 
b/framework/webtools/template/entity/ViewGeneric.ftl
index 7c163db..e907835 100644
--- a/framework/webtools/template/entity/ViewGeneric.ftl
+++ b/framework/webtools/template/entity/ViewGeneric.ftl
@@ -38,6 +38,7 @@ function ShowTab(lname) {
 }
 </script>
 
+<#assign currentFindString = currentFindString?replace("&#x2f;", "/")!>
 <div class="screenlet">
   <div class="screenlet-title-bar">
     <ul>
@@ -53,13 +54,13 @@ function ShowTab(lname) {
       <a href='<@ofbizUrl>entity/find/${entityName}</@ofbizUrl>' 
class="buttontext">${uiLabelMap.WebtoolsBackToFindScreen}</a>
       <#if enableEdit = "false">
         <#if hasCreatePermission>
-          <form 
action="<@ofbizUrl>entity/edit/${currentFindString}</@ofbizUrl>" method="get">
+          <form 
action="<@ofbizUrl>entity/edit/${currentFindString}</@ofbizUrl>" method="post">
             <input type="submit" value="${uiLabelMap.CommonEdit}" />
           </form>
         </#if>
         <#if value?has_content>
           <#if hasDeletePermission>
-            <form 
action='<@ofbizUrl>entity/change/${currentFindString}</@ofbizUrl>' 
method="delete" name="updateForm">
+            <form 
action='<@ofbizUrl>entity/change/${currentFindString}</@ofbizUrl>' 
method="post" name="updateForm">
               <input type="hidden" value="DELETE" name="_method"/>
               <#list pkNamesValuesMap.keySet() as pkName>
                 <input type="hidden" value="${pkNamesValuesMap.get(pkName)}" 
name="${pkName}"/>
diff --git a/framework/webtools/webapp/webtools/WEB-INF/controller.xml 
b/framework/webtools/webapp/webtools/WEB-INF/controller.xml
index 6e4976c..72eec1e 100644
--- a/framework/webtools/webapp/webtools/WEB-INF/controller.xml
+++ b/framework/webtools/webapp/webtools/WEB-INF/controller.xml
@@ -51,7 +51,7 @@ under the License.
     <request-map uri="entity/create/{entityName}" method="get"><security 
https="true" auth="true"/><response name="success" type="view" 
value="EditGeneric"/></request-map>
 
     <!-- form for modifying a record  -->
-    <request-map uri="entity/edit/{entityName}/{pkValues: .*}" 
method="get"><security https="true" auth="true"/><response name="success" 
type="view" value="EditGeneric" /></request-map>
+    <request-map uri="entity/edit/{entityName}/{pkValues: .*}" 
method="post"><security https="true" auth="true"/><response name="success" 
type="view" value="EditGeneric" /></request-map>
 
     <!--view relations for a given entity -->
     <request-map uri="entity/relations/{entityName}" method="get"><security 
https="true" auth="true"/><response name="success" type="view" 
value="ViewRelations" /></request-map>
diff --git 
a/framework/widget/src/main/java/org/apache/ofbiz/widget/WidgetWorker.java 
b/framework/widget/src/main/java/org/apache/ofbiz/widget/WidgetWorker.java
index 2f043bb..e359770 100644
--- a/framework/widget/src/main/java/org/apache/ofbiz/widget/WidgetWorker.java
+++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/WidgetWorker.java
@@ -27,6 +27,7 @@ import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.ofbiz.security.CsrfUtil;
 import org.apache.ofbiz.base.util.UtilCodec;
 import org.apache.ofbiz.base.util.UtilGenerics;
 import org.apache.ofbiz.base.util.UtilHttp;
@@ -115,6 +116,19 @@ public final class WidgetWorker {
         } else {
             externalWriter.append(localWriter.toString());
         }
+
+        String tokenValue = CsrfUtil.generateTokenForNonAjax(request, target);
+        if (UtilValidate.isNotEmpty(tokenValue)){
+            String currentString = externalWriter.toString();
+            if(currentString.startsWith("<form")) {
+                currentString = 
currentString.substring(currentString.lastIndexOf("\"")+1);
+            }
+            if (currentString.indexOf('?') == -1) {
+                externalWriter.append("?" + CsrfUtil.tokenNameNonAjax + "=" + 
tokenValue);
+            } else {
+                externalWriter.append("&amp;" + CsrfUtil.tokenNameNonAjax + 
"=" + tokenValue);
+            }
+        }
     }
 
     public static void appendContentUrl(Appendable writer, String location, 
HttpServletRequest request) throws IOException {
diff --git 
a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java
 
b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java
index 2a7ee14..02797ad 100644
--- 
a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java
+++ 
b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java
@@ -40,6 +40,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import org.apache.ofbiz.security.CsrfUtil;
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.StringUtil;
 import org.apache.ofbiz.base.util.UtilCodec;
@@ -1425,6 +1426,10 @@ public final class MacroFormRenderer implements 
FormStringRenderer {
             }
         }
         String focusFieldName = modelForm.getFocusFieldName();
+
+        // Generate CSRF name & value for form
+        String csrfNameValue = CsrfUtil.tokenNameNonAjax + " " 
+CsrfUtil.generateTokenForNonAjax(request, targ);
+
         StringWriter sr = new StringWriter();
         sr.append("<@renderFormOpen ");
         sr.append(" linkUrl=\"");
@@ -1455,7 +1460,9 @@ public final class MacroFormRenderer implements 
FormStringRenderer {
         sr.append(Integer.toString(viewSize));
         sr.append("\" useRowSubmit=");
         sr.append(Boolean.toString(useRowSubmit));
-        sr.append(" />");
+        sr.append(" csrfNameValue=\"");
+        sr.append(csrfNameValue);
+        sr.append("\" />");
         executeMacro(writer, sr.toString());
     }
 
@@ -2413,6 +2420,11 @@ public final class MacroFormRenderer implements 
FormStringRenderer {
             viewSizeParam = "VIEW_SIZE" + "_" + paginatorNumber;
         }
         String str = (String) context.get("_QBESTRING_");
+
+        // refresh any csrf token in the query string for pagination
+        String tokenValue = CsrfUtil.generateTokenForNonAjax(request, 
targetService);
+        str = CsrfUtil.addOrUpdateTokenInQueryString(str, tokenValue);
+
         // strip legacy viewIndex/viewSize params from the query string
         String queryString = UtilHttp.stripViewParamsFromQueryString(str, "" + 
paginatorNumber);
         // strip parameterized index/size params from the query string
diff --git a/themes/bluelight/template/Header.ftl 
b/themes/bluelight/template/Header.ftl
index 16fcea2..f4bbff9 100644
--- a/themes/bluelight/template/Header.ftl
+++ b/themes/bluelight/template/Header.ftl
@@ -28,6 +28,10 @@ under the License.
 <html lang="${docLangAttr}" dir="${langDir}" 
xmlns="http://www.w3.org/1999/xhtml";>
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <#assign csrfDefenseStrategy = 
Static["org.apache.ofbiz.entity.util.EntityUtilProperties"].getPropertyValue("security",
 "csrf.defense.strategy", delegator)>
+    <#if csrfDefenseStrategy != 
"org.apache.ofbiz.security.NoCsrfDefenseStrategy">
+        <meta name="csrf-token" content="<@csrfTokenAjax/>"/>
+    </#if>
     <title>${layoutSettings.companyName}: <#if 
(titleProperty)?has_content>${uiLabelMap[titleProperty]}<#else>${title!}</#if></title>
     <#if layoutSettings.shortcutIcon?has_content>
       <#assign shortcutIcon = layoutSettings.shortcutIcon/>
@@ -194,7 +198,7 @@ under the License.
             <#--if webSiteId?? && requestAttributes._CURRENT_VIEW_?? && 
helpTopic??-->
             <#if parameters.componentName?? && 
requestAttributes._CURRENT_VIEW_?? && helpTopic??>
               <#include 
"component://common-theme/template/includes/HelpLink.ftl" />
-              <li><a class="help-link <#if pageAvail?has_content> alert</#if>" 
href="javascript:lookup_popup1('showHelp?helpTopic=${helpTopic}&amp;portalPageId=${(parameters.portalPageId!)?html}','help'
 ,500,500);" title="${uiLabelMap.CommonHelp}"></a></li>
+              <li><a class="help-link <#if pageAvail?has_content> alert</#if>" 
href="javascript:lookup_popup1('<@ofbizUrl>showHelp?helpTopic=${helpTopic}&amp;portalPageId=${(parameters.portalPageId!)?html}</@ofbizUrl>','help'
 ,500,500);" title="${uiLabelMap.CommonHelp}"></a></li>
             </#if>
             <#if userLogin??>
               <#if "Y" == (userPreferences.COMPACT_HEADER)?default("N")>
diff --git a/themes/common-theme/template/includes/ListLocales.ftl 
b/themes/common-theme/template/includes/ListLocales.ftl
index 647090f..82c7ca7 100644
--- a/themes/common-theme/template/includes/ListLocales.ftl
+++ b/themes/common-theme/template/includes/ListLocales.ftl
@@ -36,7 +36,7 @@ under the License.
       </#if>
       <tr <#if altRow>class="alternate-row"</#if>>
         <td lang="${langAttr}" dir="${langDir}">
-          <a 
href="<@ofbizUrl>setSessionLocale</@ofbizUrl>?newLocale=${availableLocale.toString()}">
+          <a 
href="<@ofbizUrl>setSessionLocale?newLocale=${availableLocale.toString()}</@ofbizUrl>">
               ${availableLocale.getDisplayName(availableLocale)}
               &nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp; [${langAttr}]</a>
         </td>
diff --git a/themes/common-theme/template/macro/CsvFormMacroLibrary.ftl 
b/themes/common-theme/template/macro/CsvFormMacroLibrary.ftl
index cadd70e..b371b19 100644
--- a/themes/common-theme/template/macro/CsvFormMacroLibrary.ftl
+++ b/themes/common-theme/template/macro/CsvFormMacroLibrary.ftl
@@ -54,7 +54,7 @@ under the License.
 <#macro renderEmptyFormDataMessage message></#macro>
 <#macro renderSingleFormFieldTitle></#macro>
 
-<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField></#macro>
+<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField csrfNameValue></#macro>
 <#macro renderFormClose></#macro>
 <#macro renderMultiFormClose></#macro>
 
diff --git a/themes/common-theme/template/macro/FoFormMacroLibrary.ftl 
b/themes/common-theme/template/macro/FoFormMacroLibrary.ftl
index 948203f..29189db 100644
--- a/themes/common-theme/template/macro/FoFormMacroLibrary.ftl
+++ b/themes/common-theme/template/macro/FoFormMacroLibrary.ftl
@@ -80,7 +80,7 @@ under the License.
 <#macro renderEmptyFormDataMessage message></#macro>
 <#macro renderSingleFormFieldTitle><!--title form--></#macro>
 
-<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField></#macro>
+<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField csrfNameValue></#macro>
 <#macro renderFormClose></#macro>
 <#macro renderMultiFormClose></#macro>
 
diff --git a/themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl 
b/themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl
index 060fd20..9e6c62c 100644
--- a/themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl
+++ b/themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl
@@ -243,8 +243,14 @@ under the License.
 </#macro>
 <#macro renderSingleFormFieldTitle></#macro>
 
-<#macro renderFormOpen linkUrl formType name viewIndexField viewSizeField 
viewIndex viewSize targetWindow="" containerId="" containerStyle="" 
autocomplete="" useRowSubmit="" focusFieldName="" hasRequiredField="">
+<#macro renderFormOpen linkUrl formType name viewIndexField viewSizeField 
viewIndex viewSize targetWindow="" containerId="" containerStyle="" 
autocomplete="" useRowSubmit="" focusFieldName="" hasRequiredField="" 
csrfNameValue="">
   <form method="post" action="${linkUrl}"<#if formType=="upload"> 
enctype="multipart/form-data"</#if><#if targetWindow?has_content> 
target="${targetWindow}"</#if><#if containerId?has_content> 
id="${containerId}"</#if> <#if focusFieldName?has_content> 
data-focus-field="${focusFieldName}"</#if> class="<#if 
containerStyle?has_content>${containerStyle}<#else>basic-form</#if><#if 
hasRequiredField?has_content> requireValidation</#if>" 
onsubmit="javascript:submitFormDisableSubmits(this)"<#if au [...]
+    <#if csrfNameValue?has_content>
+      <#assign result = csrfNameValue?matches(r"(\w+) (\w+)")>
+      <#if result>
+        <input type="hidden" name="${result?groups[1]}" 
value="${result?groups[2]}"/>
+      </#if>
+    </#if>
     <#if useRowSubmit?has_content && useRowSubmit>
       <input type="hidden" name="_useRowSubmit" value="Y"/>
       <#if linkUrl?index_of("VIEW_INDEX") &lt;= 0 && 
linkUrl?index_of(viewIndexField) &lt;= 0>
diff --git a/themes/common-theme/template/macro/TextFormMacroLibrary.ftl 
b/themes/common-theme/template/macro/TextFormMacroLibrary.ftl
index 228611e..0e97938 100644
--- a/themes/common-theme/template/macro/TextFormMacroLibrary.ftl
+++ b/themes/common-theme/template/macro/TextFormMacroLibrary.ftl
@@ -54,7 +54,7 @@ under the License.
 <#macro renderEmptyFormDataMessage message></#macro>
 <#macro renderSingleFormFieldTitle></#macro>
 
-<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField></#macro>
+<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField csrfNameValue></#macro>
 <#macro renderFormClose></#macro>
 <#macro renderMultiFormClose></#macro>
 
diff --git a/themes/common-theme/template/macro/XlsFormMacroLibrary.ftl 
b/themes/common-theme/template/macro/XlsFormMacroLibrary.ftl
index 0998073..0472f2d 100644
--- a/themes/common-theme/template/macro/XlsFormMacroLibrary.ftl
+++ b/themes/common-theme/template/macro/XlsFormMacroLibrary.ftl
@@ -59,7 +59,7 @@ under the License.
 
 <#macro renderSingleFormFieldTitle></#macro>
 
-<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField></#macro>
+<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField csrfNameValue></#macro>
 <#macro renderFormClose></#macro>
 <#macro renderMultiFormClose></#macro>
 
diff --git a/themes/common-theme/template/macro/XmlFormMacroLibrary.ftl 
b/themes/common-theme/template/macro/XmlFormMacroLibrary.ftl
index b8cbc51..acc2f28 100644
--- a/themes/common-theme/template/macro/XmlFormMacroLibrary.ftl
+++ b/themes/common-theme/template/macro/XmlFormMacroLibrary.ftl
@@ -62,7 +62,7 @@ under the License.
 <#macro renderEmptyFormDataMessage message></#macro>
 <#macro renderSingleFormFieldTitle></#macro>
 
-<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField></#macro>
+<#macro renderFormOpen linkUrl formType targetWindow containerId 
containerStyle autocomplete name viewIndexField viewSizeField viewIndex 
viewSize useRowSubmit focusFieldName hasRequiredField csrfNameValue></#macro>
 <#macro renderFormClose></#macro>
 <#macro renderMultiFormClose></#macro>
 
diff --git a/themes/common-theme/webapp/common/js/util/OfbizUtil.js 
b/themes/common-theme/webapp/common/js/util/OfbizUtil.js
index f268519..7636760 100644
--- a/themes/common-theme/webapp/common/js/util/OfbizUtil.js
+++ b/themes/common-theme/webapp/common/js/util/OfbizUtil.js
@@ -25,6 +25,16 @@ var AJAX_REQUEST_TIMEOUT = 5000;
 
 // Add observers on DOM ready.
 $(document).ready(function() {
+    // add CSRF token to jQuery AJAX calls to the same domain
+    jQuery.ajaxPrefilter(function(options, _, jqXHR) {
+      var token;
+      if (!options.crossDomain) {
+        token = jQuery("meta[name='csrf-token']").attr("content")
+        if (token) {
+          return jqXHR.setRequestHeader("X-CSRF-Token", token);
+        }
+      }
+    });
     //initializing UI combobox dropdown by overriding its methods.
     ajaxAutoCompleteDropDown();
     // bindObservers will add observer on passed html section when DOM is 
ready.
@@ -1218,7 +1228,7 @@ function getJSONuiLabels(requiredLabels, callback) {
     }
 }
 /**
- * Read the requiered uiLabel from the uiLabelXml Resource
+ * Read the required uiLabel from the uiLabelXml Resource
  * @param uiResource String
  * @param errUiLabel String
  * @returns String with Label
diff --git a/themes/flatgrey/template/Header.ftl 
b/themes/flatgrey/template/Header.ftl
index 8920f07..bbe4eb3 100644
--- a/themes/flatgrey/template/Header.ftl
+++ b/themes/flatgrey/template/Header.ftl
@@ -24,6 +24,10 @@ under the License.
 <html lang="${docLangAttr}" dir="${langDir}" 
xmlns="http://www.w3.org/1999/xhtml";>
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <#assign csrfDefenseStrategy = 
Static["org.apache.ofbiz.entity.util.EntityUtilProperties"].getPropertyValue("security",
 "csrf.defense.strategy", delegator)>
+    <#if csrfDefenseStrategy != 
"org.apache.ofbiz.security.NoCsrfDefenseStrategy">
+        <meta name="csrf-token" content="<@csrfTokenAjax/>"/>
+    </#if>
     <title>${layoutSettings.companyName}: <#if 
(titleProperty)?has_content>${uiLabelMap[titleProperty]}<#else>${title!}</#if></title>
     <#if layoutSettings.shortcutIcon?has_content>
       <#assign shortcutIcon = layoutSettings.shortcutIcon/>
@@ -156,7 +160,7 @@ under the License.
           <#---if webSiteId?? && requestAttributes._CURRENT_VIEW_?? && 
helpTopic??-->
           <#if parameters.componentName?? && 
requestAttributes._CURRENT_VIEW_?? && helpTopic??>
             <#include 
"component://common-theme/template/includes/HelpLink.ftl" />
-            <li><a <#if pageAvail?has_content>class="alert"</#if> 
href="javascript:lookup_popup1('showHelp?helpTopic=${helpTopic}&amp;portalPageId=${(parameters.portalPageId!)?html}','help'
 ,500,500);">${uiLabelMap.CommonHelp}</a></li>
+            <li><a <#if pageAvail?has_content>class="alert"</#if> 
href="javascript:lookup_popup1('<@ofbizUrl>showHelp?helpTopic=${helpTopic}&amp;portalPageId=${(parameters.portalPageId!)?html}</@ofbizUrl>','help'
 ,500,500);">${uiLabelMap.CommonHelp}</a></li>
           </#if>
           </ul>
       </li>
diff --git a/themes/rainbowstone/template/includes/Header.ftl 
b/themes/rainbowstone/template/includes/Header.ftl
index bb1ad5e..93a8500 100644
--- a/themes/rainbowstone/template/includes/Header.ftl
+++ b/themes/rainbowstone/template/includes/Header.ftl
@@ -24,6 +24,10 @@ under the License.
 <html lang="${docLangAttr}" dir="${langDir}" 
xmlns="http://www.w3.org/1999/xhtml";>
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <#assign csrfDefenseStrategy = 
Static["org.apache.ofbiz.entity.util.EntityUtilProperties"].getPropertyValue("security",
 "csrf.defense.strategy", delegator)>
+    <#if csrfDefenseStrategy != 
"org.apache.ofbiz.security.NoCsrfDefenseStrategy">
+        <meta name="csrf-token" content="<@csrfTokenAjax/>"/>
+    </#if>
     <title>${layoutSettings.companyName}: <#if 
(titleProperty)?has_content>${uiLabelMap[titleProperty]}<#else>${title!}</#if></title>
 <#if layoutSettings.shortcutIcon?has_content>
     <#assign shortcutIcon = layoutSettings.shortcutIcon/>
diff --git a/themes/rainbowstone/template/includes/TopAppBar.ftl 
b/themes/rainbowstone/template/includes/TopAppBar.ftl
index e82c73b..90cc979 100644
--- a/themes/rainbowstone/template/includes/TopAppBar.ftl
+++ b/themes/rainbowstone/template/includes/TopAppBar.ftl
@@ -238,7 +238,7 @@ under the License.
         <div id="main-nav-bar-right">
             <div id="company-logo"></div>
             <#if parameters.componentName?exists && 
requestAttributes._CURRENT_VIEW_?exists && helpTopic?exists>
-                <a class="dark-color" title="${uiLabelMap.CommonHelp}" 
href="javascript:lookup_popup1('showHelp?helpTopic=${helpTopic}&amp;portalPageId=${(parameters.portalPageId!)?html}','help'
 ,500,500);"><img class="appbar-btn-img" id="help-btn" 
src="/rainbowstone/images/help.svg" alt="Help"></a>
+                <a class="dark-color" title="${uiLabelMap.CommonHelp}" 
href="javascript:lookup_popup1('<@ofbizUrl>showHelp?helpTopic=${helpTopic}&amp;portalPageId=${(parameters.portalPageId!)?html}</@ofbizUrl>','help'
 ,500,500);"><img class="appbar-btn-img" id="help-btn" 
src="/rainbowstone/images/help.svg" alt="Help"></a>
             </#if>
 
             <#include "component://rainbowstone/template/includes/Avatar.ftl"/>
diff --git a/themes/tomahawk/template/AppBarClose.ftl 
b/themes/tomahawk/template/AppBarClose.ftl
index 7475102..c79b4fb 100644
--- a/themes/tomahawk/template/AppBarClose.ftl
+++ b/themes/tomahawk/template/AppBarClose.ftl
@@ -75,7 +75,7 @@ under the License.
       <#--if webSiteId?? && requestAttributes._CURRENT_VIEW_?? && 
helpTopic??-->
       <#if parameters.componentName?? && requestAttributes._CURRENT_VIEW_?? && 
helpTopic??>
         <#include "component://common-theme/template/includes/HelpLink.ftl" />
-        <li><a class="help-link <#if pageAvail?has_content> alert</#if>" 
href="javascript:lookup_popup1('showHelp?helpTopic=${helpTopic}&amp;portalPageId=${(parameters.portalPageId!)?html}','help'
 ,500,500);" title="${uiLabelMap.CommonHelp}"></a></li>
+        <li><a class="help-link <#if pageAvail?has_content> alert</#if>" 
href="javascript:lookup_popup1('<@ofbizUrl>showHelp?helpTopic=${helpTopic}&amp;portalPageId=${(parameters.portalPageId!)?html}</@ofbizUrl>','help'
 ,500,500);" title="${uiLabelMap.CommonHelp}"></a></li>
       </#if>
       <li><a 
href="<@ofbizUrl>logout</@ofbizUrl>">${uiLabelMap.CommonLogout}</a></li>
       <li><a 
href="<@ofbizUrl>ListVisualThemes</@ofbizUrl>">${uiLabelMap.CommonVisualThemes}</a></li>
diff --git a/themes/tomahawk/template/Header.ftl 
b/themes/tomahawk/template/Header.ftl
index 3376614..d01ae9c 100644
--- a/themes/tomahawk/template/Header.ftl
+++ b/themes/tomahawk/template/Header.ftl
@@ -28,6 +28,10 @@ under the License.
 <html lang="${docLangAttr}" dir="${langDir}" 
xmlns="http://www.w3.org/1999/xhtml";>
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <#assign csrfDefenseStrategy = 
Static["org.apache.ofbiz.entity.util.EntityUtilProperties"].getPropertyValue("security",
 "csrf.defense.strategy", delegator)>
+    <#if csrfDefenseStrategy != 
"org.apache.ofbiz.security.NoCsrfDefenseStrategy">
+        <meta name="csrf-token" content="<@csrfTokenAjax/>"/>
+    </#if>
     <title>${layoutSettings.companyName}: <#if 
(titleProperty)?has_content>${uiLabelMap[titleProperty]}<#else>${title!}</#if></title>
     <#if layoutSettings.shortcutIcon?has_content>
       <#assign shortcutIcon = layoutSettings.shortcutIcon/>

Reply via email to