summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorFrédéric Guillot <fred@kanboard.net>2018-01-29 15:56:30 -0800
committerFrédéric Guillot <fred@kanboard.net>2018-01-29 15:56:30 -0800
commit9ddefa979a12aff2334d6e7048e142cfdef5bb89 (patch)
tree30416f103ba88c7bdf1039c9d40085a7a784ddc0 /app
parent90984d6bb9b3bd508e0ca7f8c0ee07d304679fb5 (diff)
Add CSRF check for task and project files upload
Diffstat (limited to 'app')
-rw-r--r--app/Controller/BaseController.php7
-rw-r--r--app/Controller/ProjectFileController.php1
-rw-r--r--app/Controller/TaskFileController.php1
-rw-r--r--app/Core/Http/Request.php11
-rw-r--r--app/Core/Security/Token.php42
-rw-r--r--app/Helper/AppHelper.php5
-rw-r--r--app/Template/project_file/create.php1
-rw-r--r--app/Template/task_file/create.php1
8 files changed, 61 insertions, 8 deletions
diff --git a/app/Controller/BaseController.php b/app/Controller/BaseController.php
index 43ecfaab..1433ec14 100644
--- a/app/Controller/BaseController.php
+++ b/app/Controller/BaseController.php
@@ -26,6 +26,13 @@ abstract class BaseController extends Base
}
}
+ protected function checkReusableCSRFParam()
+ {
+ if (! $this->token->validateReusableCSRFToken($this->request->getRawValue('csrf_token'))) {
+ throw new AccessForbiddenException();
+ }
+ }
+
/**
* Check webhook token
*
diff --git a/app/Controller/ProjectFileController.php b/app/Controller/ProjectFileController.php
index 83c7779f..a3e23f04 100644
--- a/app/Controller/ProjectFileController.php
+++ b/app/Controller/ProjectFileController.php
@@ -32,6 +32,7 @@ class ProjectFileController extends BaseController
*/
public function save()
{
+ $this->checkReusableCSRFParam();
$project = $this->getProject();
$result = $this->projectFileModel->uploadFiles($project['id'], $this->request->getFileInfo('files'));
diff --git a/app/Controller/TaskFileController.php b/app/Controller/TaskFileController.php
index ff0c299e..4c489238 100644
--- a/app/Controller/TaskFileController.php
+++ b/app/Controller/TaskFileController.php
@@ -51,6 +51,7 @@ class TaskFileController extends BaseController
*/
public function save()
{
+ $this->checkReusableCSRFParam();
$task = $this->getTask();
$result = $this->taskFileModel->uploadFiles($task['id'], $this->request->getFileInfo('files'));
diff --git a/app/Core/Http/Request.php b/app/Core/Http/Request.php
index 44bfdbe6..f7d29ab9 100644
--- a/app/Core/Http/Request.php
+++ b/app/Core/Http/Request.php
@@ -112,6 +112,17 @@ class Request extends Base
}
/**
+ * Get POST value without modification
+ *
+ * @param $name
+ * @return mixed|null
+ */
+ public function getRawValue($name)
+ {
+ return isset($this->post[$name]) ? $this->post[$name] : null;
+ }
+
+ /**
* Get the raw body of the HTTP request
*
* @access public
diff --git a/app/Core/Security/Token.php b/app/Core/Security/Token.php
index 9b0c5769..5efc6201 100644
--- a/app/Core/Security/Token.php
+++ b/app/Core/Security/Token.php
@@ -25,21 +25,25 @@ class Token extends Base
}
/**
- * Generate and store a CSRF token in the current session
+ * Generate and store a one-time CSRF token
*
* @access public
* @return string Random token
*/
public function getCSRFToken()
{
- if (! session_exists('csrf')) {
- session_set('csrf', []);
- }
-
- $nonce = self::getToken();
- session_merge('csrf', [$nonce => true]);
+ return $this->createSessionToken('csrf');
+ }
- return $nonce;
+ /**
+ * Generate and store a reusable CSRF token
+ *
+ * @access public
+ * @return string
+ */
+ public function getReusableCSRFToken()
+ {
+ return $this->createSessionToken('pcsrf');
}
/**
@@ -60,4 +64,26 @@ class Token extends Base
return false;
}
+
+ public function validateReusableCSRFToken($token)
+ {
+ $tokens = session_get('pcsrf');
+ if (isset($tokens[$token])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function createSessionToken($key)
+ {
+ if (! session_exists($key)) {
+ session_set($key, []);
+ }
+
+ $nonce = self::getToken();
+ session_merge($key, [$nonce => true]);
+
+ return $nonce;
+ }
}
diff --git a/app/Helper/AppHelper.php b/app/Helper/AppHelper.php
index 3cefd1c5..3a0a2428 100644
--- a/app/Helper/AppHelper.php
+++ b/app/Helper/AppHelper.php
@@ -12,6 +12,11 @@ use Kanboard\Core\Base;
*/
class AppHelper extends Base
{
+ public function getToken()
+ {
+ return $this->token;
+ }
+
public function isAjax()
{
return $this->request->isAjax();
diff --git a/app/Template/project_file/create.php b/app/Template/project_file/create.php
index de35f87c..74c5fa70 100644
--- a/app/Template/project_file/create.php
+++ b/app/Template/project_file/create.php
@@ -3,6 +3,7 @@
</div>
<?= $this->app->component('file-upload', array(
+ 'csrf' => $this->app->getToken()->getReusableCSRFToken(),
'maxSize' => $max_size,
'url' => $this->url->to('ProjectFileController', 'save', array('project_id' => $project['id'])),
'labelDropzone' => t('Drag and drop your files here'),
diff --git a/app/Template/task_file/create.php b/app/Template/task_file/create.php
index eebb08eb..46fc7d66 100644
--- a/app/Template/task_file/create.php
+++ b/app/Template/task_file/create.php
@@ -3,6 +3,7 @@
</div>
<?= $this->app->component('file-upload', array(
+ 'csrf' => $this->app->getToken()->getReusableCSRFToken(),
'maxSize' => $max_size,
'url' => $this->url->to('TaskFileController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
'labelDropzone' => t('Drag and drop your files here'),