CVE-2013-7251: Cross-Site Request Forgery (CSRF) (CWE-352)
value: Multiple cross-site request forgery (CSRF) vulnerabilities in ProjectForge before 5.3 allow remote attackers to hijack the authentication of arbitrary users via vectors related to (1) web/admin/, (2) web/core/, (3) web/dialog/, (4) web/fibu/, (5) web/mobile/, (6) web/task/, or (7) web/wicket/.
CWE description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
Published: 2014-01-02T14:59Z
Repository: https://github.com/micromata/projectforge-webapp
Language: Java
Files changed: src/main/java/org/projectforge/web/admin/SetupForm.java, src/main/java/org/projectforge/web/admin/SetupImportForm.java, src/main/java/org/projectforge/web/admin/SetupPage.html, src/main/java/org/projectforge/web/admin/SystemUpdateForm.java, src/main/java/org/projectforge/web/admin/SystemUpdatePage.html, src/main/java/org/projectforge/web/core/NavTopPanel.html, src/main/java/org/projectforge/web/core/NavTopPanel.java, src/main/java/org/projectforge/web/dialog/ModalDialog.html, src/main/java/org/projectforge/web/dialog/ModalDialog.java, src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.html, src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.java, src/main/java/org/projectforge/web/mobile/AbstractMobileEditForm.java, src/main/java/org/projectforge/web/mobile/AbstractMobileEditPage.html, src/main/java/org/projectforge/web/mobile/AbstractMobileListForm.java, src/main/java/org/projectforge/web/mobile/AbstractMobileListPage.html, src/main/java/org/projectforge/web/task/TaskTreeForm.java, src/main/java/org/projectforge/web/task/TaskTreePage.html, src/main/java/org/projectforge/web/wicket/CsrfTokenHandler.java, src/main/java/org/projectforge/web/wicket/components/DropFileContainer.html, src/main/java/org/projectforge/web/wicket/components/DropFileContainer.java
Commit date: 2013-12-06 00:14:24 +0100
Commit message: CSRF protection.

Diff: diff --git a/src/main/java/org/projectforge/web/admin/SetupForm.java b/src/main/java/org/projectforge/web/admin/SetupForm.java
index 23bf99459..dc44fcefc 100644
--- a/src/main/java/org/projectforge/web/admin/SetupForm.java
+++ b/src/main/java/org/projectforge/web/admin/SetupForm.java
@@ -38,10 +38,11 @@ import org.apache.wicket.validation.IValidator;
 import org.projectforge.core.Configuration;
 import org.projectforge.core.ConfigurationDO;
 import org.projectforge.database.InitDatabaseDao;
 import org.projectforge.user.UserDao;
 import org.projectforge.web.wicket.AbstractForm;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.WicketUtils;
 import org.projectforge.web.wicket.bootstrap.GridBuilder;
 import org.projectforge.web.wicket.components.MaxLengthTextField;
 import org.projectforge.web.wicket.components.RequiredMaxLengthTextField;
 import org.projectforge.web.wicket.components.SingleButtonPanel;
@@ -84,13 +85,19 @@ public class SetupForm extends AbstractForm<SetupForm, SetupPage>
   @SuppressWarnings("unused")
   private String passwordRepeat;
 
   private String encryptedPassword;
 
+  /**
+   * Cross site request forgery token.
+   */
+  private final CsrfTokenHandler csrfTokenHandler;
+
   public SetupForm(final SetupPage parentPage)
   {
     super(parentPage, "setupform");
+    csrfTokenHandler = new CsrfTokenHandler(this);
   }
 
   @Override
   @SuppressWarnings("serial")
   protected void init()
@@ -225,20 +232,28 @@ public class SetupForm extends AbstractForm<SetupForm, SetupPage>
     {
       final Button finishButton = new Button(SingleButtonPanel.WICKET_ID, new Model<String>("finish")) {
         @Override
         public final void onSubmit()
         {
+          csrfTokenHandler.onSubmit();
           parentPage.finishSetup();
         }
       };
       final SingleButtonPanel finishButtonPanel = new SingleButtonPanel(actionButtons.newChildId(), finishButton,
           getString("administration.setup.finish"), SingleButtonPanel.DEFAULT_SUBMIT);
       actionButtons.add(finishButtonPanel);
       setDefaultButton(finishButton);
     }
   }
 
+  @Override
+  protected void onSubmit()
+  {
+    super.onSubmit();
+    csrfTokenHandler.onSubmit();
+  }
+
   public SetupTarget getSetupMode()
   {
     return setupMode;
   }
 
diff --git a/src/main/java/org/projectforge/web/admin/SetupImportForm.java b/src/main/java/org/projectforge/web/admin/SetupImportForm.java
index f4df9dd9c..d2a50d017 100644
--- a/src/main/java/org/projectforge/web/admin/SetupImportForm.java
+++ b/src/main/java/org/projectforge/web/admin/SetupImportForm.java
@@ -27,10 +27,11 @@ import org.apache.wicket.markup.html.form.Button;
 import org.apache.wicket.markup.html.form.upload.FileUploadField;
 import org.apache.wicket.markup.repeater.RepeatingView;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.util.lang.Bytes;
 import org.projectforge.web.wicket.AbstractForm;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.bootstrap.GridBuilder;
 import org.projectforge.web.wicket.components.SingleButtonPanel;
 import org.projectforge.web.wicket.flowlayout.FieldsetPanel;
 import org.projectforge.web.wicket.flowlayout.FileUploadPanel;
 
@@ -40,14 +41,27 @@ public class SetupImportForm extends AbstractForm<SetupImportForm, SetupPage>
 
   protected FileUploadField fileUploadField;
 
   protected String filename;
 
+  /**
+   * Cross site request forgery token.
+   */
+  private final CsrfTokenHandler csrfTokenHandler;
+
   public SetupImportForm(final SetupPage parentPage)
   {
     super(parentPage, "importform");
     initUpload(Bytes.megabytes(100));
+    csrfTokenHandler = new CsrfTokenHandler(this);
+  }
+
+  @Override
+  protected void onSubmit()
+  {
+    super.onSubmit();
+    csrfTokenHandler.onSubmit();
   }
 
   @Override
   @SuppressWarnings("serial")
   protected void init()
diff --git a/src/main/java/org/projectforge/web/admin/SetupPage.html b/src/main/java/org/projectforge/web/admin/SetupPage.html
index 2a1333f30..67f79c790 100644
--- a/src/main/java/org/projectforge/web/admin/SetupPage.html
+++ b/src/main/java/org/projectforge/web/admin/SetupPage.html
@@ -19,10 +19,11 @@
             <div wicket:id="feedback"></div>
             <wicket:container wicket:id="flowform">[the form fields]</wicket:container>
             <div class="button_bar">
               <wicket:container wicket:id="buttons">[action buttons]</wicket:container>
             </div>
+            <input type="hidden" wicket:id="csrfToken" />
           </form>
         </div>
       </div>
 
       <div id="upload" class="tab-pane">
@@ -30,10 +31,11 @@
           <div wicket:id="feedback"></div>
           <wicket:container wicket:id="flowform">[the form fields]</wicket:container>
           <div class="button_bar">
             <wicket:container wicket:id="buttons">[action buttons]</wicket:container>
           </div>
+          <input type="hidden" wicket:id="csrfToken" />
         </form>
       </div>
     </div>
   </wicket:extend>
 </body>
diff --git a/src/main/java/org/projectforge/web/admin/SystemUpdateForm.java b/src/main/java/org/projectforge/web/admin/SystemUpdateForm.java
index 34e9bbd9e..e8ed6aec9 100644
--- a/src/main/java/org/projectforge/web/admin/SystemUpdateForm.java
+++ b/src/main/java/org/projectforge/web/admin/SystemUpdateForm.java
@@ -36,10 +36,11 @@ import org.apache.wicket.model.PropertyModel;
 import org.projectforge.Version;
 import org.projectforge.continuousdb.UpdateEntry;
 import org.projectforge.continuousdb.UpdatePreCheckStatus;
 import org.projectforge.web.HtmlHelper;
 import org.projectforge.web.wicket.AbstractForm;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.bootstrap.GridBuilder;
 import org.projectforge.web.wicket.components.SingleButtonPanel;
 import org.projectforge.web.wicket.flowlayout.CheckBoxPanel;
 import org.projectforge.web.wicket.flowlayout.FieldsetPanel;
 import org.projectforge.web.wicket.flowlayout.MyComponentsRepeater;
@@ -52,18 +53,24 @@ public class SystemUpdateForm extends AbstractForm<SystemUpdateForm, SystemUpdat
 
   public boolean showOldUpdateScripts;
 
   private GridBuilder gridBuilder;
 
+  /**
+   * Cross site request forgery token.
+   */
+  private final CsrfTokenHandler csrfTokenHandler;
+
   /**
    * List to create content menu in the desired order before creating the RepeatingView.
    */
   protected MyComponentsRepeater<SingleButtonPanel> actionButtons;
 
   public SystemUpdateForm(final SystemUpdatePage parentPage)
   {
     super(parentPage);
+    csrfTokenHandler = new CsrfTokenHandler(this);
   }
 
   @Override
   @SuppressWarnings("serial")
   protected void init()
@@ -163,6 +170,13 @@ public class SystemUpdateForm extends AbstractForm<SystemUpdateForm, SystemUpdat
   public void onBeforeRender()
   {
     super.onBeforeRender();
     actionButtons.render();
   }
+
+  @Override
+  protected void onSubmit()
+  {
+    super.onSubmit();
+    csrfTokenHandler.onSubmit();
+  }
 }
diff --git a/src/main/java/org/projectforge/web/admin/SystemUpdatePage.html b/src/main/java/org/projectforge/web/admin/SystemUpdatePage.html
index 84942e07f..ba6c2f66b 100644
--- a/src/main/java/org/projectforge/web/admin/SystemUpdatePage.html
+++ b/src/main/java/org/projectforge/web/admin/SystemUpdatePage.html
@@ -45,9 +45,10 @@
       </div>
       <wicket:container wicket:id="flowform">[the form fields]</wicket:container>
       <div class="button_bar">
         <wicket:container wicket:id="buttons">[action buttons]</wicket:container>
       </div>
+      <input type="hidden" wicket:id="csrfToken" />
     </form>
   </wicket:extend>
 </body>
 </html>
\ No newline at end of file
diff --git a/src/main/java/org/projectforge/web/core/NavTopPanel.html b/src/main/java/org/projectforge/web/core/NavTopPanel.html
index 19498d2f9..eb1079824 100644
--- a/src/main/java/org/projectforge/web/core/NavTopPanel.html
+++ b/src/main/java/org/projectforge/web/core/NavTopPanel.html
@@ -37,10 +37,11 @@
                 </ul></li>
             </ul>
           </div>
           <form class="navbar-search pull-left" wicket:id="searchForm" autocomplete="off">
             <input type="text" class="search-query span2" placeholder="Search" wicket:id="searchField">
+            <input type="hidden" wicket:id="csrfToken" />
           </form>
           <ul class="nav pull-right">
             <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown"><span wicket:id="user">[Kai Reinhard]</span><b
                 class="caret"></b></a>
               <ul class="dropdown-menu">
diff --git a/src/main/java/org/projectforge/web/core/NavTopPanel.java b/src/main/java/org/projectforge/web/core/NavTopPanel.java
index 74f63e682..c099387a0 100644
--- a/src/main/java/org/projectforge/web/core/NavTopPanel.java
+++ b/src/main/java/org/projectforge/web/core/NavTopPanel.java
@@ -57,10 +57,11 @@ import org.projectforge.web.dialog.ModalDialog;
 import org.projectforge.web.doc.DocumentationPage;
 import org.projectforge.web.mobile.MenuMobilePage;
 import org.projectforge.web.user.ChangePasswordPage;
 import org.projectforge.web.user.MyAccountEditPage;
 import org.projectforge.web.wicket.AbstractSecuredPage;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.FeedbackPage;
 import org.projectforge.web.wicket.MySession;
 import org.projectforge.web.wicket.WicketUtils;
 import org.projectforge.web.wicket.flowlayout.FieldsetPanel;
 
@@ -80,10 +81,15 @@ public class NavTopPanel extends NavAbstractPanel
 
   private final UserXmlPreferencesCache userXmlPreferencesCache;
 
   private BookmarkDialog bookmarkDialog;
 
+  /**
+   * Cross site request forgery token.
+   */
+  private CsrfTokenHandler csrfTokenHandler;
+
   public NavTopPanel(final String id, final UserXmlPreferencesCache userXmlPreferencesCache, final AccessChecker accessChecker)
   {
     super(id);
     this.userXmlPreferencesCache = userXmlPreferencesCache;
     this.accessChecker = accessChecker;
@@ -115,17 +121,19 @@ public class NavTopPanel extends NavAbstractPanel
        * @see org.apache.wicket.markup.html.form.Form#onSubmit()
        */
       @Override
       protected void onSubmit()
       {
+        csrfTokenHandler.onSubmit();
         if (StringUtils.isNotBlank(searchString) == true) {
           final SearchPage searchPage = new SearchPage(new PageParameters(), searchString);
           setResponsePage(searchPage);
         }
         super.onSubmit();
       }
     };
+    csrfTokenHandler = new CsrfTokenHandler(searchForm);
     add(searchForm);
     final TextField<String> searchField = new TextField<String>("searchField", new PropertyModel<String>(searchForm, "searchString"));
     WicketUtils.setPlaceHolderAttribute(searchField, getString("search.search"));
     searchForm.add(searchField);
     add(layoutSettingsMenuLink);
diff --git a/src/main/java/org/projectforge/web/dialog/ModalDialog.html b/src/main/java/org/projectforge/web/dialog/ModalDialog.html
index 68aae466f..4197e7cc5 100644
--- a/src/main/java/org/projectforge/web/dialog/ModalDialog.html
+++ b/src/main/java/org/projectforge/web/dialog/ModalDialog.html
@@ -1,19 +1,22 @@
 <wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
   <div class="modal hide" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" wicket:id="mainContainer">
     <wicket:container wicket:id="mainSubContainer">
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
-        <h3 id="myModalLabel" wicket:id="titleContainer"><span wicket:id="titleText">[title]</span></h3>
+        <h3 id="myModalLabel" wicket:id="titleContainer">
+          <span wicket:id="titleText">[title]</span>
+        </h3>
       </div>
       <form wicket:id="form" autocomplete="off">
         <div class="modal-body" wicket:id="gridContent">
           <div wicket:id="formFeedback"></div>
           <wicket:container wicket:id="flowform">[The content]</wicket:container>
         </div>
         <div class="modal-footer" wicket:id="buttonBar">
           <wicket:container wicket:id="actionButtons" />
         </div>
+        <input type="hidden" wicket:id="csrfToken" />
       </form>
     </wicket:container>
   </div>
 </wicket:panel>
\ No newline at end of file
diff --git a/src/main/java/org/projectforge/web/dialog/ModalDialog.java b/src/main/java/org/projectforge/web/dialog/ModalDialog.java
index f4b543bc8..13bfda4b7 100644
--- a/src/main/java/org/projectforge/web/dialog/ModalDialog.java
+++ b/src/main/java/org/projectforge/web/dialog/ModalDialog.java
@@ -37,10 +37,11 @@ import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.panel.FeedbackPanel;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.projectforge.web.core.NavTopPanel;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.WicketUtils;
 import org.projectforge.web.wicket.bootstrap.GridBuilder;
 import org.projectforge.web.wicket.components.SingleButtonPanel;
 import org.projectforge.web.wicket.flowlayout.MyComponentsRepeater;
 
@@ -95,10 +96,15 @@ public abstract class ModalDialog extends Panel
   /**
    * List to create action buttons in the desired order before creating the RepeatingView.
    */
   protected MyComponentsRepeater<Component> actionButtons;
 
+  /**
+   * Cross site request forgery token.
+   */
+  protected CsrfTokenHandler csrfTokenHandler;
+
   /**
    * @param id
    */
   public ModalDialog(final String id)
   {
@@ -229,10 +235,11 @@ public abstract class ModalDialog extends Panel
   {
     mainContainer.add(new AjaxEventBehavior("hidden") {
       @Override
       protected void onEvent(final AjaxRequestTarget target)
       {
+        csrfTokenHandler.onSubmit();
         handleCloseEvent(target);
       }
     });
     return this;
   }
@@ -286,10 +293,11 @@ public abstract class ModalDialog extends Panel
     return this;
   }
 
   public void close(final AjaxRequestTarget target)
   {
+    csrfTokenHandler.onSubmit();
     target.appendJavaScript("$('#" + getMainContainerMarkupId() + "').modal('hide');");
   }
 
   /**
    * Add the content to the AjaxRequestTarget if the content is changed.
@@ -364,18 +372,20 @@ public abstract class ModalDialog extends Panel
 
   @SuppressWarnings("serial")
   protected void init(final Form< ? > form)
   {
     this.form = form;
+    csrfTokenHandler = new CsrfTokenHandler(form);
     mainSubContainer.add(form);
     form.add(gridContentContainer);
     form.add(buttonBarContainer);
     if (showCancelButton == true) {
       final SingleButtonPanel cancelButton = appendNewAjaxActionButton(new AjaxCallback() {
         @Override
         public void callback(final AjaxRequestTarget target)
         {
+          csrfTokenHandler.onSubmit();
           onCancelButtonSubmit(target);
           close(target);
         }
       }, getString("cancel"), SingleButtonPanel.CANCEL);
       cancelButton.getButton().setDefaultFormProcessing(false);
@@ -383,18 +393,20 @@ public abstract class ModalDialog extends Panel
     closeButtonPanel = appendNewAjaxActionButton(new AjaxFormSubmitCallback() {
 
       @Override
       public void callback(final AjaxRequestTarget target)
       {
+        csrfTokenHandler.onSubmit();
         if (onCloseButtonSubmit(target)) {
           close(target);
         }
       }
 
       @Override
       public void onError(final AjaxRequestTarget target, final Form< ? > form)
       {
+        csrfTokenHandler.onSubmit();
         ModalDialog.this.onError(target, form);
       }
     }, closeButtonLabel != null ? closeButtonLabel : getString("close"), SingleButtonPanel.NORMAL);
     buttonBarContainer.add(actionButtons.getRepeatingView());
     form.setDefaultButton(closeButtonPanel.getButton());
@@ -414,10 +426,11 @@ public abstract class ModalDialog extends Panel
     container.add(formFeedback);
   }
 
   protected void ajaxError(final String error, final AjaxRequestTarget target)
   {
+    csrfTokenHandler.onSubmit();
     form.error(error);
     target.add(formFeedback);
   }
 
   /**
@@ -425,10 +438,11 @@ public abstract class ModalDialog extends Panel
    * upper right cross).
    * @param target
    */
   protected void handleCloseEvent(final AjaxRequestTarget target)
   {
+    csrfTokenHandler.onSubmit();
   }
 
   /**
    * Called if user hit the cancel button.
    * @param target
@@ -503,10 +517,11 @@ public abstract class ModalDialog extends Panel
       private static final long serialVersionUID = -5306532706450731336L;
 
       @Override
       protected void onSubmit(final AjaxRequestTarget target, final Form< ? > form)
       {
+        csrfTokenHandler.onSubmit();
         ajaxCallback.callback(target);
       }
 
       @Override
       protected void onError(final AjaxRequestTarget target, final Form< ? > form)
diff --git a/src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.html b/src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.html
index c9c0dc396..8837dcac5 100644
--- a/src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.html
+++ b/src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.html
@@ -30,10 +30,13 @@
             <td style="vertical-align: middle;" wicket:id="deleteEntry">[delete button]</td>
           </tr>
         </tbody>
       </table>
       <div>
-      <wicket:message key="rest" />: <span wicket:id="restValue">[-1234,00]</span></div>
+        <wicket:message key="rest" />
+        : <span wicket:id="restValue">[-1234,00]</span>
+      </div>
+      <input type="hidden" wicket:id="csrfToken" />
     </form>
   </wicket:panel>
 </body>
 </html>
\ No newline at end of file
diff --git a/src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.java b/src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.java
index cceacbdda..ff00fa656 100644
--- a/src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.java
+++ b/src/main/java/org/projectforge/web/fibu/RechnungCostEditTablePanel.java
@@ -52,10 +52,11 @@ import org.projectforge.fibu.RechnungsPositionDO;
 import org.projectforge.fibu.kost.Kost1DO;
 import org.projectforge.fibu.kost.Kost2DO;
 import org.projectforge.fibu.kost.Kost2Dao;
 import org.projectforge.fibu.kost.KostZuweisungDO;
 import org.projectforge.fibu.kost.KostZuweisungenCopyHelper;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.WicketAjaxUtils;
 import org.projectforge.web.wicket.WicketUtils;
 import org.projectforge.web.wicket.components.MinMaxNumberField;
 import org.projectforge.web.wicket.components.SingleButtonPanel;
 import org.projectforge.web.wicket.converter.CurrencyConverter;
@@ -83,21 +84,35 @@ public class RechnungCostEditTablePanel extends Panel
 
   private AbstractRechnungsPositionDO position;
 
   MyAjaxComponentHolder ajaxComponents = new MyAjaxComponentHolder();
 
+  /**
+   * Cross site request forgery token.
+   */
+  private final CsrfTokenHandler csrfTokenHandler;
+
   /**
    * @param id
    */
+  @SuppressWarnings("serial")
   public RechnungCostEditTablePanel(final String id)
   {
     super(id);
     feedbackPanel = new FeedbackPanel("feedback");
     ajaxComponents.register(feedbackPanel);
     add(feedbackPanel);
-    this.form = new Form<AbstractRechnungsPositionDO>("form");
+    this.form = new Form<AbstractRechnungsPositionDO>("form") {
+      @Override
+      protected void onSubmit()
+      {
+        super.onSubmit();
+        csrfTokenHandler.onSubmit();
+      }
+    };
     add(form);
+    csrfTokenHandler = new CsrfTokenHandler(form);
     rows = new RepeatingView("rows");
     form.add(rows);
   }
 
   /**
diff --git a/src/main/java/org/projectforge/web/mobile/AbstractMobileEditForm.java b/src/main/java/org/projectforge/web/mobile/AbstractMobileEditForm.java
index 208577dad..ff80e6cef 100644
--- a/src/main/java/org/projectforge/web/mobile/AbstractMobileEditForm.java
+++ b/src/main/java/org/projectforge/web/mobile/AbstractMobileEditForm.java
@@ -26,10 +26,11 @@ package org.projectforge.web.mobile;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.SubmitLink;
 import org.apache.wicket.markup.html.panel.FeedbackPanel;
 import org.apache.wicket.markup.repeater.RepeatingView;
 import org.projectforge.core.AbstractBaseDO;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.mobileflowlayout.MobileGridBuilder;
 
 public abstract class AbstractMobileEditForm<O extends AbstractBaseDO< ? >, P extends AbstractMobileEditPage< ? , ? , ? >> extends
 AbstractMobileForm<O, P>
 {
@@ -37,14 +38,27 @@ AbstractMobileForm<O, P>
 
   protected O data;
 
   protected MobileGridBuilder gridBuilder;
 
+  /**
+   * Cross site request forgery token.
+   */
+  private final CsrfTokenHandler csrfTokenHandler;
+
   public AbstractMobileEditForm(final P parentPage, final O data)
   {
     super(parentPage);
     this.data = data;
+    csrfTokenHandler = new CsrfTokenHandler(this);
+  }
+
+  @Override
+  protected void onSubmit()
+  {
+    super.onSubmit();
+    csrfTokenHandler.onSubmit();
   }
 
   public O getData()
   {
     return this.data;
diff --git a/src/main/java/org/projectforge/web/mobile/AbstractMobileEditPage.html b/src/main/java/org/projectforge/web/mobile/AbstractMobileEditPage.html
index 9ed7f0f49..ee47a24c8 100644
--- a/src/main/java/org/projectforge/web/mobile/AbstractMobileEditPage.html
+++ b/src/main/java/org/projectforge/web/mobile/AbstractMobileEditPage.html
@@ -17,10 +17,11 @@
         <wicket:container wicket:id="flowform">[the form fields]</wicket:container>
         <wicket:child />
         <p>
           <a wicket:id="submitButton" rel="external" data-role="button"><wicket:container wicket:id="label">[create or update]</wicket:container></a>
         </p>
+        <input type="hidden" wicket:id="csrfToken" />
       </form>
     </div>
   </wicket:extend>
 </body>
 </html>
\ No newline at end of file
diff --git a/src/main/java/org/projectforge/web/mobile/AbstractMobileListForm.java b/src/main/java/org/projectforge/web/mobile/AbstractMobileListForm.java
index 832cb1763..41557f4b4 100644
--- a/src/main/java/org/projectforge/web/mobile/AbstractMobileListForm.java
+++ b/src/main/java/org/projectforge/web/mobile/AbstractMobileListForm.java
@@ -25,20 +25,26 @@ package org.projectforge.web.mobile;
 
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.model.PropertyModel;
 import org.projectforge.core.BaseSearchFilter;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 
 public abstract class AbstractMobileListForm<F extends BaseSearchFilter, P extends AbstractMobileListPage< ? , ? , ? >> extends
 AbstractMobileForm<AbstractMobileListForm< ? , ? >, AbstractMobileListPage< ? , ? , ? >>
 {
   private static final long serialVersionUID = -2521426347126048630L;
 
   private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(AbstractMobileListForm.class);
 
   protected F filter;
 
+  /**
+   * Cross site request forgery token.
+   */
+  private final CsrfTokenHandler csrfTokenHandler;
+
   @SuppressWarnings("unchecked")
   public AbstractMobileListForm(final AbstractMobileListPage< ? , ? , ? > parentPage)
   {
     super(parentPage);
     final String userPrefFilterKey = this.getClass().getSimpleName() + ".filter";
@@ -49,10 +55,18 @@ AbstractMobileForm<AbstractMobileListForm< ? , ? >, AbstractMobileListPage< ? ,
     }
     if (filter == null) {
       filter = newFilter();
       parentPage.putUserPrefEntry(userPrefFilterKey, filter, true);
     }
+    csrfTokenHandler = new CsrfTokenHandler(this);
+  }
+
+  @Override
+  protected void onSubmit()
+  {
+    super.onSubmit();
+    csrfTokenHandler.onSubmit();
   }
 
   protected void init()
   {
     add(new TextField<String>("searchField", new PropertyModel<String>(filter, "searchString")).add(AttributeModifier.replace(
diff --git a/src/main/java/org/projectforge/web/mobile/AbstractMobileListPage.html b/src/main/java/org/projectforge/web/mobile/AbstractMobileListPage.html
index 94d27929e..b4fa9c08f 100644
--- a/src/main/java/org/projectforge/web/mobile/AbstractMobileListPage.html
+++ b/src/main/java/org/projectforge/web/mobile/AbstractMobileListPage.html
@@ -4,14 +4,17 @@
 <meta content="yes" name="apple-mobile-web-app-capable" />
 <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
 </head>
 
 <body>
-<wicket:extend>
-  <form wicket:id="form" autocomplete="off">
-  <div data-role="fieldcontain" id="searchfield"><input type="text" data-type="search" wicket:id="searchField" id="search" placeholder="Suche" /></div>
-  </form>
-  <wicket:container wicket:id="listViewPage">
-  </wicket:container>
-</wicket:extend>
+  <wicket:extend>
+    <form wicket:id="form" autocomplete="off">
+      <div data-role="fieldcontain" id="searchfield">
+        <input type="text" data-type="search" wicket:id="searchField" id="search" placeholder="Suche" />
+      </div>
+      <input type="hidden" wicket:id="csrfToken" />
+    </form>
+    <wicket:container wicket:id="listViewPage">
+    </wicket:container>
+  </wicket:extend>
 </body>
 </html>
diff --git a/src/main/java/org/projectforge/web/task/TaskTreeForm.java b/src/main/java/org/projectforge/web/task/TaskTreeForm.java
index 5d7613d03..56759e3e5 100644
--- a/src/main/java/org/projectforge/web/task/TaskTreeForm.java
+++ b/src/main/java/org/projectforge/web/task/TaskTreeForm.java
@@ -29,10 +29,11 @@ import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.PropertyModel;
 import org.projectforge.task.TaskFilter;
 import org.projectforge.web.wicket.AbstractForm;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.WebConstants;
 import org.projectforge.web.wicket.WicketUtils;
 import org.projectforge.web.wicket.bootstrap.GridBuilder;
 import org.projectforge.web.wicket.bootstrap.GridSize;
 import org.projectforge.web.wicket.components.SingleButtonPanel;
@@ -63,10 +64,15 @@ public class TaskTreeForm extends AbstractForm<TaskFilter, TaskTreePage>
 
   private SingleButtonPanel searchButtonPanel;
 
   protected GridBuilder gridBuilder;
 
+  /**
+   * Cross site request forgery token.
+   */
+  private final CsrfTokenHandler csrfTokenHandler;
+
   @Override
   @SuppressWarnings("serial")
   protected void init()
   {
     super.init();
@@ -129,11 +135,12 @@ public class TaskTreeForm extends AbstractForm<TaskFilter, TaskTreePage>
         {
           getParentPage().onListViewSubmit();
         }
       };
 
-      listViewButtonPanel = new SingleButtonPanel(actionButtons.newChildId(), listViewButton, getString("listView"), SingleButtonPanel.NORMAL);
+      listViewButtonPanel = new SingleButtonPanel(actionButtons.newChildId(), listViewButton, getString("listView"),
+          SingleButtonPanel.NORMAL);
       actionButtons.add(listViewButtonPanel);
     }
     {
       final Button searchButton = new Button("button", new Model<String>("search")) {
         @Override
@@ -151,10 +158,11 @@ public class TaskTreeForm extends AbstractForm<TaskFilter, TaskTreePage>
   }
 
   public TaskTreeForm(final TaskTreePage parentPage)
   {
     super(parentPage);
+    csrfTokenHandler = new CsrfTokenHandler(this);
   }
 
   @Override
   public void onBeforeRender()
   {
@@ -196,10 +204,11 @@ public class TaskTreeForm extends AbstractForm<TaskFilter, TaskTreePage>
 
   @Override
   protected void onSubmit()
   {
     super.onSubmit();
+    csrfTokenHandler.onSubmit();
     parentPage.refresh();
   }
 
   @SuppressWarnings("serial")
   private class MyCheckBoxPanel extends CheckBoxPanel
diff --git a/src/main/java/org/projectforge/web/task/TaskTreePage.html b/src/main/java/org/projectforge/web/task/TaskTreePage.html
index 92e466c8d..fcbbb4248 100644
--- a/src/main/java/org/projectforge/web/task/TaskTreePage.html
+++ b/src/main/java/org/projectforge/web/task/TaskTreePage.html
@@ -21,10 +21,11 @@
 
       <div class="button_bar">
         <wicket:container wicket:id="actionButtons">[cancel] [search]</wicket:container>
       </div>
       <div wicket:id="tree">[tree]</div>
+      <input type="hidden" wicket:id="csrfToken" />
     </form>
     <div class="alert alert-info" wicket:id="info">[Click on row to select one task.]</div>
   </wicket:extend>
 
 </body>
diff --git a/src/main/java/org/projectforge/web/wicket/CsrfTokenHandler.java b/src/main/java/org/projectforge/web/wicket/CsrfTokenHandler.java
index 838bc1244..ebe962e29 100644
--- a/src/main/java/org/projectforge/web/wicket/CsrfTokenHandler.java
+++ b/src/main/java/org/projectforge/web/wicket/CsrfTokenHandler.java
@@ -27,11 +27,11 @@ import java.io.Serializable;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.wicket.Session;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.HiddenField;
-import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
 import org.projectforge.core.InternalErrorException;
 
 /**
  * Every form should use this handler for preventing cross site request forgery attacks.
  * @author Kai Reinhard (k.reinhard@micromata.de)
@@ -41,19 +41,20 @@ public class CsrfTokenHandler implements Serializable
 {
   private static final long serialVersionUID = -9129345307409567900L;
 
   private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(CsrfTokenHandler.class);
 
-  private HiddenField<String> csrfTokenField;
+  private final String csrfToken;
 
   /**
    * The given form should contain a hidden field named 'csrfToken'.
    * @param form
    */
   public CsrfTokenHandler(final Form< ? > form)
   {
-    form.add(csrfTokenField = new HiddenField<String>("csrfToken", Model.of(getCsrfSessionToken())));
+    csrfToken = getCsrfSessionToken();
+    form.add(new HiddenField<String>("csrfToken", new PropertyModel<String>(this, "csrfToken")));
   }
 
   /**
    * This parameter should be set as hidden field in every formular and should be tested on every submit action for preventing CSRF attacks.
    * @return the randomized cross site request forgery token.
@@ -69,15 +70,14 @@ public class CsrfTokenHandler implements Serializable
    * @see org.apache.wicket.markup.html.form.Form#onSubmit()
    */
   public void onSubmit()
   {
     final String sessionCsrfToken = getCsrfSessionToken();
-    final String postedCsrfToken = this.csrfTokenField.getInput();
-    if (StringUtils.equals(sessionCsrfToken, postedCsrfToken) == false) {
+    if (StringUtils.equals(sessionCsrfToken, csrfToken) == false) {
       log.error("Cross site request forgery alert. csrf token doesn't match! session csrf token="
           + sessionCsrfToken
           + ", posted csrf token="
-          + postedCsrfToken);
+          + csrfToken);
       throw new InternalErrorException("errorpage.csrfError");
     }
   }
 }
diff --git a/src/main/java/org/projectforge/web/wicket/components/DropFileContainer.html b/src/main/java/org/projectforge/web/wicket/components/DropFileContainer.html
index d93687322..5e895610a 100644
--- a/src/main/java/org/projectforge/web/wicket/components/DropFileContainer.html
+++ b/src/main/java/org/projectforge/web/wicket/components/DropFileContainer.html
@@ -1,11 +1,13 @@
 <wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
   <div class="pf_dnd" wicket:id="main">
     <input type="file" id="fileselect" class="pf_fileselect" />
-    <div class="pf_filedrag"><wicket:message key="drop" /></div>
+    <div class="pf_filedrag">
+      <wicket:message key="drop" />
+    </div>
     <form wicket:id="hiddenForm" class="pf_hiddenForm">
       <textarea class="pf_text" wicket:id="importString"></textarea>
       <textarea class="pf_name" wicket:id="importFileName"></textarea>
-      <input type="submit" class="pf_submit" wicket:id="submitButton" />
+      <input type="submit" class="pf_submit" wicket:id="submitButton" /> <input type="hidden" wicket:id="csrfToken" />
     </form>
   </div>
 </wicket:panel>
diff --git a/src/main/java/org/projectforge/web/wicket/components/DropFileContainer.java b/src/main/java/org/projectforge/web/wicket/components/DropFileContainer.java
index d049ad332..ff4f8ffd1 100644
--- a/src/main/java/org/projectforge/web/wicket/components/DropFileContainer.java
+++ b/src/main/java/org/projectforge/web/wicket/components/DropFileContainer.java
@@ -31,10 +31,11 @@ import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.TextArea;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.CompoundPropertyModel;
+import org.projectforge.web.wicket.CsrfTokenHandler;
 import org.projectforge.web.wicket.WicketUtils;
 
 /**
  * The panel which includes the drop behavior for several files. If the dropped file (string) was sucessfully importet, the hook method
  * {@link #onStringImport(AjaxRequestTarget, String, String)} is called.
@@ -45,21 +46,28 @@ import org.projectforge.web.wicket.WicketUtils;
 public abstract class DropFileContainer extends Panel
 {
   private static final long serialVersionUID = 3622467918922963503L;
 
   private final WebMarkupContainer main;
+
   private final String mimeType;
 
+  /**
+   * Cross site request forgery token.
+   */
+  private  CsrfTokenHandler csrfTokenHandler;
+
   /**
    * @param id
    */
   public DropFileContainer(final String id)
   {
     this(id, null);
   }
 
-  public DropFileContainer(final String id, final String mimeType) {
+  public DropFileContainer(final String id, final String mimeType)
+  {
     super(id);
     this.mimeType = mimeType;
     main = new WebMarkupContainer("main");
     add(main);
   }
@@ -80,10 +88,11 @@ public abstract class DropFileContainer extends Panel
       private static final long serialVersionUID = 6140567784494429257L;
 
       @Override
       protected void onSubmit(final AjaxRequestTarget target, final Form< ? > form)
       {
+        csrfTokenHandler.onSubmit();
         final FormBean modelObject = hiddenForm.getModel().getObject();
         onStringImport(target, modelObject.importFileName, modelObject.importString);
       }
 
       @Override
@@ -91,10 +100,11 @@ public abstract class DropFileContainer extends Panel
       {
         // nothing to do here
       }
 
     });
+    csrfTokenHandler = new CsrfTokenHandler(hiddenForm);
   }
 
   /**
    * @param content
    * @return this for chaining.

Vulnerable code:         <h3 id="myModalLabel" wicket:id="titleContainer"><span wicket:id="titleText">[title]</span></h3>
      <wicket:message key="rest" />: <span wicket:id="restValue">[-1234,00]</span></div>
    this.form = new Form<AbstractRechnungsPositionDO>("form");
<wicket:extend>
  <form wicket:id="form" autocomplete="off">
  <div data-role="fieldcontain" id="searchfield"><input type="text" data-type="search" wicket:id="searchField" id="search" placeholder="Suche" /></div>
  </form>
  <wicket:container wicket:id="listViewPage">
  </wicket:container>
</wicket:extend>
      listViewButtonPanel = new SingleButtonPanel(actionButtons.newChildId(), listViewButton, getString("listView"), SingleButtonPanel.NORMAL);
import org.apache.wicket.model.Model;
  private HiddenField<String> csrfTokenField;
    form.add(csrfTokenField = new HiddenField<String>("csrfToken", Model.of(getCsrfSessionToken())));
    final String postedCsrfToken = this.csrfTokenField.getInput();
    if (StringUtils.equals(sessionCsrfToken, postedCsrfToken) == false) {
          + postedCsrfToken);
    <div class="pf_filedrag"><wicket:message key="drop" /></div>
      <input type="submit" class="pf_submit" wicket:id="submitButton" />
  public DropFileContainer(final String id, final String mimeType) {
Fixed code: import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  private final CsrfTokenHandler csrfTokenHandler;

    csrfTokenHandler = new CsrfTokenHandler(this);
          csrfTokenHandler.onSubmit();
  @Override
  protected void onSubmit()
  {
    super.onSubmit();
    csrfTokenHandler.onSubmit();
  }

import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  private final CsrfTokenHandler csrfTokenHandler;

    csrfTokenHandler = new CsrfTokenHandler(this);
  }

  @Override
  protected void onSubmit()
  {
    super.onSubmit();
    csrfTokenHandler.onSubmit();
            <input type="hidden" wicket:id="csrfToken" />
          <input type="hidden" wicket:id="csrfToken" />
import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  private final CsrfTokenHandler csrfTokenHandler;

    csrfTokenHandler = new CsrfTokenHandler(this);

  @Override
  protected void onSubmit()
  {
    super.onSubmit();
    csrfTokenHandler.onSubmit();
  }
      <input type="hidden" wicket:id="csrfToken" />
            <input type="hidden" wicket:id="csrfToken" />
import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  private CsrfTokenHandler csrfTokenHandler;

        csrfTokenHandler.onSubmit();
    csrfTokenHandler = new CsrfTokenHandler(searchForm);
        <h3 id="myModalLabel" wicket:id="titleContainer">
          <span wicket:id="titleText">[title]</span>
        </h3>
        <input type="hidden" wicket:id="csrfToken" />
import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  protected CsrfTokenHandler csrfTokenHandler;

        csrfTokenHandler.onSubmit();
    csrfTokenHandler.onSubmit();
    csrfTokenHandler = new CsrfTokenHandler(form);
          csrfTokenHandler.onSubmit();
        csrfTokenHandler.onSubmit();
        csrfTokenHandler.onSubmit();
    csrfTokenHandler.onSubmit();
    csrfTokenHandler.onSubmit();
        csrfTokenHandler.onSubmit();
        <wicket:message key="rest" />
        : <span wicket:id="restValue">[-1234,00]</span>
      </div>
      <input type="hidden" wicket:id="csrfToken" />
import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  private final CsrfTokenHandler csrfTokenHandler;

  @SuppressWarnings("serial")
    this.form = new Form<AbstractRechnungsPositionDO>("form") {
      @Override
      protected void onSubmit()
      {
        super.onSubmit();
        csrfTokenHandler.onSubmit();
      }
    };
    csrfTokenHandler = new CsrfTokenHandler(form);
import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  private final CsrfTokenHandler csrfTokenHandler;

    csrfTokenHandler = new CsrfTokenHandler(this);
  }

  @Override
  protected void onSubmit()
  {
    super.onSubmit();
    csrfTokenHandler.onSubmit();
        <input type="hidden" wicket:id="csrfToken" />
import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  private final CsrfTokenHandler csrfTokenHandler;

    csrfTokenHandler = new CsrfTokenHandler(this);
  }

  @Override
  protected void onSubmit()
  {
    super.onSubmit();
    csrfTokenHandler.onSubmit();
  <wicket:extend>
    <form wicket:id="form" autocomplete="off">
      <div data-role="fieldcontain" id="searchfield">
        <input type="text" data-type="search" wicket:id="searchField" id="search" placeholder="Suche" />
      </div>
      <input type="hidden" wicket:id="csrfToken" />
    </form>
    <wicket:container wicket:id="listViewPage">
    </wicket:container>
  </wicket:extend>
import org.projectforge.web.wicket.CsrfTokenHandler;
  /**
   * Cross site request forgery token.
   */
  private final CsrfTokenHandler csrfTokenHandler;

      listViewButtonPanel = new SingleButtonPanel(actionButtons.newChildId(), listViewButton, getString("listView"),
          SingleButtonPanel.NORMAL);
    csrfTokenHandler = new CsrfTokenHandler(this);
    csrfTokenHandler.onSubmit();
      <input type="hidden" wicket:id="csrfToken" />
import org.apache.wicket.model.PropertyModel;
  private final String csrfToken;
    csrfToken = getCsrfSessionToken();
    form.add(new HiddenField<String>("csrfToken", new PropertyModel<String>(this, "csrfToken")));
    if (StringUtils.equals(sessionCsrfToken, csrfToken) == false) {
          + csrfToken);
    <div class="pf_filedrag">
      <wicket:message key="drop" />
    </div>
      <input type="submit" class="pf_submit" wicket:id="submitButton" /> <input type="hidden" wicket:id="csrfToken" />
import org.projectforge.web.wicket.CsrfTokenHandler;

  /**
   * Cross site request forgery token.
   */
  private  CsrfTokenHandler csrfTokenHandler;

  public DropFileContainer(final String id, final String mimeType)
  {
        csrfTokenHandler.onSubmit();
    csrfTokenHandler = new CsrfTokenHandler(hiddenForm);