Fixed CSRF prevention checks for REST calls, moved CSRF initialization to Bootstrap

This commit is contained in:
Duncan Sommerville 2015-02-20 13:12:49 -05:00
parent 0177e40083
commit be7cae4408
4 changed files with 33 additions and 11 deletions

View File

@ -65,13 +65,28 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
}
$view->headScript()->appendScript("var userType = '$userType';");
}
/**
* Create a global namespace to hold a session token for CSRF prevention
*/
protected function _initCsrfNamespace() {
$csrf_namespace = new Zend_Session_Namespace('csrf_namespace');
// Check if the token exists
if (!$csrf_namespace->authtoken) {
// If we don't have a token, regenerate it and set a 2 hour timeout
// Should we log the user out here if the token is expired?
$csrf_namespace->authtoken = sha1(uniqid(rand(),1));
$csrf_namespace->setExpirationSeconds(2*60*60);
}
}
/**
* Ideally, globals should be written to a single js file once
* from a php init function. This will save us from having to
* reinitialize them every request
*/
private function _initTranslationGlobals($view) {
protected function _initTranslationGlobals() {
$view = $this->getResource('view');
$view->headScript()->appendScript("var PRODUCT_NAME = '" . PRODUCT_NAME . "';");
$view->headScript()->appendScript("var USER_MANUAL_URL = '" . USER_MANUAL_URL . "';");
$view->headScript()->appendScript("var COMPANY_NAME = '" . COMPANY_NAME . "';");

View File

@ -98,6 +98,9 @@ class LoginController extends Zend_Controller_Action
{
$auth = Zend_Auth::getInstance();
$auth->clearIdentity();
// Unset all session variables relating to CSRF prevention on logout
$csrf_namespace = new Zend_Session_Namespace('csrf_namespace');
$csrf_namespace->unsetAll();
$this->_redirect('showbuilder/index');
}

View File

@ -32,8 +32,9 @@ class PluploadController extends Zend_Controller_Action
}
$csrf_namespace = new Zend_Session_Namespace('csrf_namespace');
$csrf_namespace->setExpirationSeconds(5*60*60);
$csrf_namespace->authtoken = sha1(uniqid(rand(),1));
/* Moved to be globally set in Bootstrap */
// $csrf_namespace->setExpirationSeconds(5*60*60);
// $csrf_namespace->authtoken = sha1(uniqid(rand(),1));
$csrf_element = new Zend_Form_Element_Hidden('csrf');
$csrf_element->setValue($csrf_namespace->authtoken)->setRequired('true')->removeDecorator('HtmlTag')->removeDecorator('Label');

View File

@ -148,17 +148,22 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
}
}
} else { //We have a session/identity.
// If we have an identity and we're making a RESTful request,
// we need to check the CSRF token
if ($request->_action != "get" && $request->getModuleName() == "rest") {
$tokenValid = $this->verifyCSRFToken($request->getParam("csrf_token"));
if ($_SERVER['REQUEST_METHOD'] != "GET" && $request->getModuleName() == "rest") {
$token = $request->getParam("csrf_token");
$tokenValid = $this->verifyCSRFToken($token);
if (!$tokenValid) {
$csrf_namespace = new Zend_Session_Namespace('csrf_namespace');
$csrf_namespace->authtoken = sha1(uniqid(rand(),1));
Logging::warn("Invalid CSRF token: $token");
$this->getResponse()
->setHttpResponseCode(401)
->appendBody("ERROR: CSRF token mismatch.");
return;
->appendBody("ERROR: CSRF token mismatch.")
->sendResponse();
die();
}
}
@ -202,9 +207,7 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
$current_namespace = new Zend_Session_Namespace('csrf_namespace');
$observed_csrf_token = $token;
$expected_csrf_token = $current_namespace->authtoken;
Logging::error("Observed: " . $observed_csrf_token);
Logging::error("Expected: " . $expected_csrf_token);
return ($observed_csrf_token == $expected_csrf_token);
}